@gg-web-engine/core 0.0.57 → 0.0.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/2d/components/physics/i-physics-world-2d.component.d.ts +1 -1
  2. package/dist/2d/components/physics/i-rigid-body-2d.component.d.ts +1 -1
  3. package/dist/2d/components/physics/i-trigger-2d.component.d.ts +3 -3
  4. package/dist/2d/components/rendering/i-camera-2d.component.d.ts +5 -0
  5. package/dist/2d/components/rendering/i-display-object-2d.component.d.ts +1 -1
  6. package/dist/2d/components/rendering/i-renderer-2d.component.d.ts +1 -1
  7. package/dist/2d/components/rendering/i-visual-scene-2d.component.d.ts +2 -3
  8. package/dist/2d/entities/controllers/entity-2d-positioning.animator.d.ts +2 -2
  9. package/dist/2d/entities/entity-2d.d.ts +7 -7
  10. package/dist/2d/entities/i-renderable-2d.entity.d.ts +4 -4
  11. package/dist/2d/entities/renderer-2d.entity.d.ts +2 -1
  12. package/dist/2d/entities/trigger-2d.entity.d.ts +8 -4
  13. package/dist/2d/factories.d.ts +7 -7
  14. package/dist/2d/gg-2d-world.d.ts +38 -6
  15. package/dist/2d/gg-2d-world.js +27 -21
  16. package/dist/2d/index.d.ts +3 -0
  17. package/dist/2d/index.js +3 -0
  18. package/dist/2d/level-loader.d.ts +101 -0
  19. package/dist/2d/level-loader.js +88 -0
  20. package/dist/2d/loader.d.ts +11 -0
  21. package/dist/2d/loader.js +10 -0
  22. package/dist/3d/components/physics/i-physics-world-3d.component.d.ts +5 -5
  23. package/dist/3d/components/physics/i-raycast-vehicle.component.d.ts +1 -1
  24. package/dist/3d/components/physics/i-rigid-body-3d.component.d.ts +1 -1
  25. package/dist/3d/components/physics/i-trigger-3d.component.d.ts +3 -3
  26. package/dist/3d/components/rendering/{i-camera.component.d.ts → i-camera-3d.component.d.ts} +1 -1
  27. package/dist/3d/components/rendering/i-camera-3d.component.js +1 -0
  28. package/dist/3d/components/rendering/i-display-object-3d.component.d.ts +1 -1
  29. package/dist/3d/components/rendering/i-renderer-3d.component.d.ts +1 -2
  30. package/dist/3d/components/rendering/i-visual-scene-3d.component.d.ts +3 -4
  31. package/dist/3d/entities/camera-3d.entity.d.ts +24 -0
  32. package/dist/3d/entities/camera-3d.entity.js +35 -0
  33. package/dist/3d/entities/controllers/animators/camera-3d.animator.d.ts +3 -3
  34. package/dist/3d/entities/controllers/animators/entity-3d-positioning.animator.d.ts +2 -2
  35. package/dist/3d/entities/entity-3d.d.ts +6 -6
  36. package/dist/3d/entities/gg-car/gg-car.entity.d.ts +5 -5
  37. package/dist/3d/entities/i-renderable-3d.entity.d.ts +4 -4
  38. package/dist/3d/entities/map-graph-3d.entity.d.ts +6 -6
  39. package/dist/3d/entities/raycast-vehicle-3d.entity.d.ts +3 -3
  40. package/dist/3d/entities/renderer-3d.entity.d.ts +1 -6
  41. package/dist/3d/entities/renderer-3d.entity.js +0 -15
  42. package/dist/3d/entities/surface-following.entity.d.ts +3 -3
  43. package/dist/3d/entities/surface-following.entity.js +3 -0
  44. package/dist/3d/entities/trigger-3d.entity.d.ts +8 -4
  45. package/dist/3d/factories.d.ts +14 -14
  46. package/dist/3d/gg-3d-world.d.ts +37 -9
  47. package/dist/3d/gg-3d-world.js +23 -19
  48. package/dist/3d/index.d.ts +3 -1
  49. package/dist/3d/index.js +3 -1
  50. package/dist/3d/level-loader.d.ts +300 -0
  51. package/dist/3d/level-loader.js +267 -0
  52. package/dist/3d/loader.d.ts +55 -14
  53. package/dist/3d/loader.js +37 -8
  54. package/dist/3d/loaders.d.ts +4 -4
  55. package/dist/base/blueprint/blueprint-node.d.ts +75 -0
  56. package/dist/base/blueprint/blueprint-node.js +51 -0
  57. package/dist/base/blueprint/blueprint.d.ts +123 -0
  58. package/dist/base/blueprint/blueprint.js +86 -0
  59. package/dist/base/blueprint/nodes/remove-entity.node.d.ts +26 -0
  60. package/dist/base/blueprint/nodes/remove-entity.node.js +29 -0
  61. package/dist/base/components/i-world-component.d.ts +5 -5
  62. package/dist/base/components/physics/i-body.component.d.ts +5 -5
  63. package/dist/base/components/physics/i-physics-world.component.d.ts +13 -5
  64. package/dist/base/components/physics/i-rigid-body.component.d.ts +2 -2
  65. package/dist/base/components/physics/i-trigger.component.d.ts +4 -4
  66. package/dist/base/components/rendering/i-display-object.component.d.ts +6 -6
  67. package/dist/base/components/rendering/i-renderer.component.d.ts +5 -4
  68. package/dist/base/components/rendering/i-visual-scene.component.d.ts +4 -2
  69. package/dist/base/entities/controllers/animation-mixer.d.ts +3 -3
  70. package/dist/base/entities/group.entity.d.ts +17 -0
  71. package/dist/base/entities/group.entity.js +19 -0
  72. package/dist/base/entities/i-entity.d.ts +19 -8
  73. package/dist/base/entities/i-entity.js +28 -0
  74. package/dist/base/entities/i-renderable.entity.d.ts +2 -2
  75. package/dist/base/entities/i-renderer.entity.d.ts +11 -5
  76. package/dist/base/entities/i-renderer.entity.js +15 -0
  77. package/dist/base/gg-world.d.ts +42 -5
  78. package/dist/base/gg-world.js +45 -10
  79. package/dist/base/index.d.ts +6 -0
  80. package/dist/base/index.js +6 -0
  81. package/dist/base/inputs/mouse.input.js +1 -0
  82. package/dist/base/level-loader.d.ts +217 -0
  83. package/dist/base/level-loader.js +258 -0
  84. package/dist/base/math/numbers.d.ts +2 -1
  85. package/dist/base/math/numbers.js +7 -1
  86. package/dist/base/math/point2.d.ts +17 -1
  87. package/dist/base/math/point2.js +35 -0
  88. package/dist/base/math/point3.d.ts +2 -0
  89. package/dist/base/math/point3.js +15 -1
  90. package/dist/base/models/points.d.ts +20 -16
  91. package/dist/base/models/raycasting.d.ts +52 -0
  92. package/dist/base/models/raycasting.js +1 -0
  93. package/dist/version.d.ts +1 -1
  94. package/dist/version.js +1 -1
  95. package/package.json +1 -1
  96. package/tsconfig.json +3 -1
  97. /package/dist/{3d/components/rendering/i-camera.component.js → 2d/components/rendering/i-camera-2d.component.js} +0 -0
@@ -0,0 +1,300 @@
1
+ import { LevelLoader } from '../base/level-loader';
2
+ import { Gg3dWorld, Gg3dWorldTypeDocRepo } from './gg-3d-world';
3
+ import { AxisDirection3, Point3, Point4 } from '../base';
4
+ import { DisplayObject3dOpts } from './factories';
5
+ import { Body3DOptions } from './models/body-options';
6
+ import { Shape3DDescriptor } from './models/shapes';
7
+ import { GgCarProperties } from './entities/gg-car/gg-car.entity';
8
+ import { RVEntityAxleOptions, RVEntitySharedWheelOptions } from './entities/raycast-vehicle-3d.entity';
9
+ import { MapGraphNodeType } from './entities/map-graph-3d.entity';
10
+ /**
11
+ * Shape names accepted by the built-in `"Primitive"` entity class in a 3D level JSON, via the
12
+ * sibling `shape` field on the entity (e.g. `{ class: "Primitive", shape: "BOX" }`) - the same
13
+ * `Shape3DDescriptor['shape']` values used at the engine API level, so no translation is needed
14
+ * between a level JSON and `Gg3dWorld.addPrimitiveRigidBody`.
15
+ */
16
+ export type Primitive3DShapeName = Shape3DDescriptor['shape'];
17
+ /**
18
+ * Settings shared by every primitive entity (Box, Sphere, Plane, Capsule, Cylinder, Cone)
19
+ */
20
+ export interface Primitive3DSettings {
21
+ /**
22
+ * Which primitive shape to construct
23
+ */
24
+ shape: Primitive3DShapeName;
25
+ /**
26
+ * Position of the primitive
27
+ */
28
+ position?: Point3;
29
+ /**
30
+ * Rotation of the primitive
31
+ */
32
+ rotation?: Point4;
33
+ /**
34
+ * Dimensions of the primitive (for Box)
35
+ */
36
+ dimensions?: Point3;
37
+ /**
38
+ * Radius of the primitive (for Sphere, Capsule, Cylinder, Cone)
39
+ */
40
+ radius?: number;
41
+ /**
42
+ * Height of the primitive (for Cylinder, Cone)
43
+ */
44
+ height?: number;
45
+ /**
46
+ * Centers distance of the primitive (for Capsule)
47
+ */
48
+ centersDistance?: number;
49
+ /**
50
+ * Material options for the primitive
51
+ */
52
+ material?: DisplayObject3dOpts<any>;
53
+ /**
54
+ * Physics body options, merged over sensible defaults
55
+ */
56
+ body?: Partial<Body3DOptions>;
57
+ }
58
+ /**
59
+ * Settings for a trigger entity
60
+ */
61
+ export interface Trigger3DSettings {
62
+ /**
63
+ * Position of the trigger
64
+ */
65
+ position?: Point3;
66
+ /**
67
+ * Rotation of the trigger
68
+ */
69
+ rotation?: Point4;
70
+ /**
71
+ * Dimensions of the trigger
72
+ */
73
+ dimensions: Point3;
74
+ }
75
+ /**
76
+ * Settings for a camera entity
77
+ */
78
+ export interface Camera3DSettings {
79
+ /**
80
+ * Position of the camera
81
+ */
82
+ position?: Point3;
83
+ /**
84
+ * Rotation of the camera
85
+ */
86
+ rotation?: Point4;
87
+ /**
88
+ * Field of view in degrees
89
+ */
90
+ fov?: number;
91
+ /**
92
+ * Aspect ratio (width / height)
93
+ */
94
+ aspectRatio?: number;
95
+ /**
96
+ * Near and far frustum planes
97
+ */
98
+ frustrum?: {
99
+ near: number;
100
+ far: number;
101
+ };
102
+ }
103
+ /**
104
+ * Settings for a `"GgCar"` wheel's optional visual mesh. A level JSON has no way to reference an
105
+ * existing display object component (unlike programmatic `RVEntityProperties`, whose
106
+ * `WheelDisplayOptions.displayObject` takes one directly) - instead, supplying `display` at all
107
+ * makes the `"GgCar"` generator build one itself via `visualScene.factory.createCylinder`, sized
108
+ * to that wheel's own (or its axle/shared settings') `tyreRadius`/`tyreWidth`. Omit `display`
109
+ * entirely (on both the wheel and whatever it inherits from) to leave that wheel invisible
110
+ * (physics-only), same as omitting `WheelDisplayOptions.displayObject` does programmatically.
111
+ */
112
+ export interface GgCarWheelDisplaySettings {
113
+ material?: DisplayObject3dOpts<any>;
114
+ wheelObjectDirection?: AxisDirection3;
115
+ }
116
+ /**
117
+ * JSON-friendly counterpart of `RVEntitySharedWheelOptions`: identical except `display` is a
118
+ * {@link GgCarWheelDisplaySettings} descriptor instead of a ready-made `WheelDisplayOptions`.
119
+ */
120
+ export type GgCarSharedWheelSettings = Omit<RVEntitySharedWheelOptions, 'display'> & {
121
+ display?: GgCarWheelDisplaySettings;
122
+ };
123
+ /**
124
+ * JSON-friendly counterpart of `RVEntityAxleOptions`, for the `"GgCar"` class's `wheelBase.front`/
125
+ * `wheelBase.rear`.
126
+ */
127
+ export type GgCarAxleSettings = Pick<RVEntityAxleOptions, 'halfAxleWidth' | 'axlePosition' | 'axleHeight'> & GgCarSharedWheelSettings;
128
+ /**
129
+ * JSON-friendly counterpart of one `RVEntityProperties['wheelOptions']` element, for the
130
+ * `"GgCar"` class's `wheelOptions` array.
131
+ */
132
+ export type GgCarWheelSettings = GgCarSharedWheelSettings & {
133
+ isLeft: boolean;
134
+ isFront: boolean;
135
+ position: Point3;
136
+ };
137
+ /**
138
+ * Fields of `GgCarProperties` that don't vary between its `wheelBase`/`wheelOptions` shapes -
139
+ * carried over into {@link GgCar3DSettings} as-is (already plain JSON-serializable data).
140
+ */
141
+ export interface GgCar3DCommonSettings {
142
+ suspension: GgCarProperties['suspension'];
143
+ tractionBias: GgCarProperties['tractionBias'];
144
+ mpsToRpmFactor?: GgCarProperties['mpsToRpmFactor'];
145
+ engine: GgCarProperties['engine'];
146
+ brake: GgCarProperties['brake'];
147
+ transmission: GgCarProperties['transmission'];
148
+ maxSteerAngle: GgCarProperties['maxSteerAngle'];
149
+ }
150
+ /**
151
+ * Settings for the built-in `"GgCar"` entity class (3D only): builds a box-shaped chassis rigid
152
+ * body (+ optional matching display box) and a full `GgCarEntity` on top of it - the procedural
153
+ * counterpart of the GLB-driven car construction apps do by hand (see `examples/fly-city-three-ammo`'s
154
+ * `GameFactory.generateCar`), for a car whose chassis/wheels are plain primitives rather than
155
+ * loaded meshes.
156
+ */
157
+ export type GgCar3DSettings = GgCar3DCommonSettings & {
158
+ position?: Point3;
159
+ rotation?: Point4;
160
+ /**
161
+ * The chassis's box collider/mesh. `body` is merged over a default dynamic body (same shape as
162
+ * `Primitive3DSettings.body`, but with `mass: 800` instead of `1`, since a `mass: 1` chassis is
163
+ * unrealistically light for a car).
164
+ */
165
+ chassis: {
166
+ dimensions: Point3;
167
+ material?: DisplayObject3dOpts<any>;
168
+ body?: Partial<Body3DOptions>;
169
+ };
170
+ } & ({
171
+ wheelBase: {
172
+ shared?: GgCarSharedWheelSettings;
173
+ front: GgCarAxleSettings;
174
+ rear: GgCarAxleSettings;
175
+ };
176
+ wheelOptions?: undefined;
177
+ sharedWheelOptions?: undefined;
178
+ } | {
179
+ wheelOptions: GgCarWheelSettings[];
180
+ sharedWheelOptions?: GgCarSharedWheelSettings;
181
+ wheelBase?: undefined;
182
+ });
183
+ /**
184
+ * JSON-friendly counterpart of `MapGraphNodeType`: identical except `loadOptions` may be omitted
185
+ * (defaulting to `{}`) rather than required, since most nodes need none of it.
186
+ */
187
+ export type MapGraphNodeJson = Omit<MapGraphNodeType, 'loadOptions'> & {
188
+ loadOptions?: MapGraphNodeType['loadOptions'];
189
+ };
190
+ /**
191
+ * Settings for the built-in `"MapGraph"` entity class (3D only): builds a `MapGraph` from plain
192
+ * node data and wraps it in a ready-to-use `MapGraph3dEntity`. `graph` mirrors the two
193
+ * `MapGraph` factory methods - a flat (optionally closed-loop) path via `nodes`, or a rectangular
194
+ * `grid` - since both already take plain-data node arrays. The resulting entity doesn't implement
195
+ * `IPositionable3d` (each node carries its own absolute `position`/`rotation`), so there's no
196
+ * `position`/`rotation` field here - and its `loaderCursor$` still needs to be driven at runtime
197
+ * from whatever entity's position should determine which nodes are loaded (see
198
+ * `gg-engine-level-json` skill's "MapGraph" section).
199
+ */
200
+ export interface MapGraph3DSettings {
201
+ graph: {
202
+ type?: 'array';
203
+ nodes: MapGraphNodeJson[];
204
+ closed?: boolean;
205
+ } | {
206
+ type: 'grid';
207
+ grid: MapGraphNodeJson[][];
208
+ };
209
+ /** Depth in the graph to load - see `Gg3dMapGraphEntityOptions.loadDepth` (default `5`) */
210
+ loadDepth?: number;
211
+ /** Extra unload-delay depth - see `Gg3dMapGraphEntityOptions.inertia` (default `0`) */
212
+ inertia?: number;
213
+ /** Max nodes loaded per tick - see `Gg3dMapGraphEntityOptions.maxNodesLoadingPerTick` (default `1`) */
214
+ maxNodesLoadingPerTick?: number;
215
+ /** Ticks/second of the internal load-scheduling clock - see `MapGraph3dEntity.loadRateLimit` (default `1`) */
216
+ loadRateLimit?: number;
217
+ }
218
+ /**
219
+ * 3D level loader: registers the built-in primitive/trigger/camera/car/map-graph entity classes
220
+ * and dispatches `LevelJson` entities to them (or to custom classes registered via
221
+ * `registerClass`).
222
+ * @template TypeDoc - The type document repository
223
+ */
224
+ export declare class Gg3dLevelLoader<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> extends LevelLoader<Point3, Point4, TypeDoc> {
225
+ protected readonly world: Gg3dWorld<TypeDoc>;
226
+ constructor(world: Gg3dWorld<TypeDoc>);
227
+ /**
228
+ * Register the built-in classes for primitives, triggers, and cameras
229
+ */
230
+ private registerDefaultClasses;
231
+ /**
232
+ * Turn a `Primitive3DSettings` (`shape` plus shape-specific fields) into the `Shape3DDescriptor`
233
+ * consumed by `Gg3dWorld.addPrimitiveRigidBody`.
234
+ * @param settings - The primitive settings, as parsed from a `"Primitive"` entity's `shape` +
235
+ * `config`
236
+ * @returns The shape descriptor
237
+ */
238
+ private buildShapeDescriptor;
239
+ /**
240
+ * Create a primitive entity (both display object and physics body) from a shape descriptor.
241
+ * `Shape3DDescriptor` (no mesh-only segment options) is used for both the visual and the
242
+ * physics representation, same as `Gg3dWorld.addPrimitiveRigidBody`'s own shortcut methods.
243
+ * @param world - The world instance
244
+ * @param shape - The shape descriptor
245
+ * @param settings - Position/rotation/material/body settings shared by all primitives
246
+ * @returns The created entity
247
+ */
248
+ private createPrimitive;
249
+ /**
250
+ * Create a trigger entity: a `Trigger3dEntity` wrapping the raw physics trigger component, so
251
+ * the app can subscribe to `onEntityEntered`/`onEntityLeft` without any extra wiring - see the
252
+ * base `LevelLoader` docs for how it's parented for level-lifecycle cleanup.
253
+ * @param world - The world instance
254
+ * @param settings - The trigger settings
255
+ * @returns The created trigger entity
256
+ */
257
+ private createTrigger;
258
+ /**
259
+ * Create a camera entity: a `Camera3dEntity` wrapping the raw camera component, not attached to
260
+ * any renderer/canvas (a level JSON has no notion of one - `world.addRenderer(entity.camera,
261
+ * canvas)` once the app has a canvas). Parented under the level's group entity, so it's torn
262
+ * down along with the rest of the level - put a camera meant to outlive a level swap in a
263
+ * separate, never-unloaded level instead (see `gg-engine-level-json`'s "Camera" section).
264
+ * @param world - The world instance
265
+ * @param settings - The camera settings
266
+ * @returns The created camera entity
267
+ */
268
+ private createCamera;
269
+ /**
270
+ * Build a `WheelDisplayOptions` for one `"GgCar"` wheel/axle from its (already shared-merged)
271
+ * settings, via `visualScene.factory.createCylinder`. Returns `undefined` (no visual wheel,
272
+ * physics-only) if `display` wasn't specified at all, or there's no visual scene to build one
273
+ * against.
274
+ * @param world - The world instance
275
+ * @param wheelSettings - The wheel's own settings, already merged over whatever it inherits
276
+ * from `wheelBase.shared`/`sharedWheelOptions`
277
+ * @returns The resolved display options, or `undefined`
278
+ */
279
+ private resolveWheelDisplay;
280
+ /**
281
+ * Create a `"GgCar"` entity: a box chassis rigid body (+ optional matching display box) wrapped
282
+ * in a full `GgCarEntity`, with each wheel's optional visual mesh built from its settings (see
283
+ * {@link resolveWheelDisplay}) rather than referencing an existing display object component,
284
+ * which a level JSON has no way to do.
285
+ * @param world - The world instance
286
+ * @param settings - The car settings
287
+ * @returns The created car entity
288
+ */
289
+ private createGgCar;
290
+ /**
291
+ * Create a `"MapGraph"` entity: a `MapGraph` built from plain node data (a flat/looped path or
292
+ * a rectangular grid, see {@link MapGraph3DSettings}), wrapped in a ready-to-use
293
+ * `MapGraph3dEntity`. The app still has to drive `loaderCursor$` itself once the level is
294
+ * loaded - see `gg-engine-level-json`'s "MapGraph" section.
295
+ * @param world - The world instance
296
+ * @param settings - The map graph settings
297
+ * @returns The created map graph entity
298
+ */
299
+ private createMapGraph;
300
+ }
@@ -0,0 +1,267 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { LevelLoader } from '../base/level-loader';
13
+ import { Trigger3dEntity } from './entities/trigger-3d.entity';
14
+ import { Camera3dEntity } from './entities/camera-3d.entity';
15
+ import { GgCarEntity } from './entities/gg-car/gg-car.entity';
16
+ import { MapGraph, MapGraph3dEntity, } from './entities/map-graph-3d.entity';
17
+ const defaultBodyOptions = {
18
+ dynamic: true,
19
+ mass: 1,
20
+ restitution: 0.2,
21
+ friction: 0.5,
22
+ ownCollisionGroups: 'all',
23
+ interactWithCollisionGroups: 'all',
24
+ };
25
+ const defaultCarChassisBodyOptions = Object.assign(Object.assign({}, defaultBodyOptions), { mass: 800 });
26
+ /** Fallback tyre size used only to size a `"GgCar"` wheel's auto-generated cylinder mesh when
27
+ * neither the wheel nor its shared wheel settings specify one - independent of the physics
28
+ * wheel's own default (`RaycastVehicle3dEntity`'s internal `wheeelDefaults`) applied when a
29
+ * wheel's `tyreRadius`/`tyreWidth` is left unset entirely. */
30
+ const defaultWheelDisplaySize = { tyreRadius: 0.4, tyreWidth: 0.3 };
31
+ /**
32
+ * 3D level loader: registers the built-in primitive/trigger/camera/car/map-graph entity classes
33
+ * and dispatches `LevelJson` entities to them (or to custom classes registered via
34
+ * `registerClass`).
35
+ * @template TypeDoc - The type document repository
36
+ */
37
+ export class Gg3dLevelLoader extends LevelLoader {
38
+ constructor(world) {
39
+ super(world);
40
+ this.world = world;
41
+ this.registerDefaultClasses();
42
+ }
43
+ /**
44
+ * Register the built-in classes for primitives, triggers, and cameras
45
+ */
46
+ registerDefaultClasses() {
47
+ this.registerClass('Primitive', (world, settings) => this.createPrimitive(world, this.buildShapeDescriptor(settings), settings));
48
+ this.registerClass('Trigger', this.createTrigger.bind(this));
49
+ this.registerClass('Camera', this.createCamera.bind(this));
50
+ this.registerClass('GgCar', this.createGgCar.bind(this));
51
+ this.registerClass('MapGraph', this.createMapGraph.bind(this));
52
+ }
53
+ /**
54
+ * Turn a `Primitive3DSettings` (`shape` plus shape-specific fields) into the `Shape3DDescriptor`
55
+ * consumed by `Gg3dWorld.addPrimitiveRigidBody`.
56
+ * @param settings - The primitive settings, as parsed from a `"Primitive"` entity's `shape` +
57
+ * `config`
58
+ * @returns The shape descriptor
59
+ */
60
+ buildShapeDescriptor(settings) {
61
+ switch (settings.shape) {
62
+ case 'BOX':
63
+ if (!settings.dimensions) {
64
+ throw new Error('Dimensions are required for BOX primitive');
65
+ }
66
+ return { shape: 'BOX', dimensions: settings.dimensions };
67
+ case 'SPHERE':
68
+ if (settings.radius === undefined) {
69
+ throw new Error('Radius is required for SPHERE primitive');
70
+ }
71
+ return { shape: 'SPHERE', radius: settings.radius };
72
+ case 'PLANE':
73
+ return { shape: 'PLANE' };
74
+ case 'CAPSULE':
75
+ if (settings.radius === undefined) {
76
+ throw new Error('Radius is required for CAPSULE primitive');
77
+ }
78
+ if (settings.centersDistance === undefined) {
79
+ throw new Error('Centers distance is required for CAPSULE primitive');
80
+ }
81
+ return { shape: 'CAPSULE', radius: settings.radius, centersDistance: settings.centersDistance };
82
+ case 'CYLINDER':
83
+ if (settings.radius === undefined) {
84
+ throw new Error('Radius is required for CYLINDER primitive');
85
+ }
86
+ if (settings.height === undefined) {
87
+ throw new Error('Height is required for CYLINDER primitive');
88
+ }
89
+ return { shape: 'CYLINDER', radius: settings.radius, height: settings.height };
90
+ case 'CONE':
91
+ if (settings.radius === undefined) {
92
+ throw new Error('Radius is required for CONE primitive');
93
+ }
94
+ if (settings.height === undefined) {
95
+ throw new Error('Height is required for CONE primitive');
96
+ }
97
+ return { shape: 'CONE', radius: settings.radius, height: settings.height };
98
+ default:
99
+ throw new Error(`Unknown primitive shape "${settings.shape}"`);
100
+ }
101
+ }
102
+ /**
103
+ * Create a primitive entity (both display object and physics body) from a shape descriptor.
104
+ * `Shape3DDescriptor` (no mesh-only segment options) is used for both the visual and the
105
+ * physics representation, same as `Gg3dWorld.addPrimitiveRigidBody`'s own shortcut methods.
106
+ * @param world - The world instance
107
+ * @param shape - The shape descriptor
108
+ * @param settings - Position/rotation/material/body settings shared by all primitives
109
+ * @returns The created entity
110
+ */
111
+ createPrimitive(world, shape, settings) {
112
+ const { position, rotation, material, body } = settings;
113
+ return world.addPrimitiveRigidBody({ shape, body: Object.assign(Object.assign({}, defaultBodyOptions), body) }, position, rotation, material);
114
+ }
115
+ /**
116
+ * Create a trigger entity: a `Trigger3dEntity` wrapping the raw physics trigger component, so
117
+ * the app can subscribe to `onEntityEntered`/`onEntityLeft` without any extra wiring - see the
118
+ * base `LevelLoader` docs for how it's parented for level-lifecycle cleanup.
119
+ * @param world - The world instance
120
+ * @param settings - The trigger settings
121
+ * @returns The created trigger entity
122
+ */
123
+ createTrigger(world, settings) {
124
+ var _a;
125
+ const { position, rotation, dimensions } = settings;
126
+ const shape = { shape: 'BOX', dimensions };
127
+ const trigger = (_a = world.physicsWorld) === null || _a === void 0 ? void 0 : _a.factory.createTrigger(shape, { position, rotation });
128
+ if (!trigger) {
129
+ return undefined;
130
+ }
131
+ const entity = new Trigger3dEntity(trigger);
132
+ if (position) {
133
+ entity.position = position;
134
+ }
135
+ if (rotation) {
136
+ entity.rotation = rotation;
137
+ }
138
+ return entity;
139
+ }
140
+ /**
141
+ * Create a camera entity: a `Camera3dEntity` wrapping the raw camera component, not attached to
142
+ * any renderer/canvas (a level JSON has no notion of one - `world.addRenderer(entity.camera,
143
+ * canvas)` once the app has a canvas). Parented under the level's group entity, so it's torn
144
+ * down along with the rest of the level - put a camera meant to outlive a level swap in a
145
+ * separate, never-unloaded level instead (see `gg-engine-level-json`'s "Camera" section).
146
+ * @param world - The world instance
147
+ * @param settings - The camera settings
148
+ * @returns The created camera entity
149
+ */
150
+ createCamera(world, settings) {
151
+ var _a;
152
+ const { position, rotation, fov, aspectRatio, frustrum } = settings;
153
+ const camera = (_a = world.visualScene) === null || _a === void 0 ? void 0 : _a.factory.createPerspectiveCamera({ fov, aspectRatio, frustrum });
154
+ if (!camera) {
155
+ return undefined;
156
+ }
157
+ const entity = new Camera3dEntity(camera);
158
+ if (position) {
159
+ entity.position = position;
160
+ }
161
+ if (rotation) {
162
+ entity.rotation = rotation;
163
+ }
164
+ return entity;
165
+ }
166
+ /**
167
+ * Build a `WheelDisplayOptions` for one `"GgCar"` wheel/axle from its (already shared-merged)
168
+ * settings, via `visualScene.factory.createCylinder`. Returns `undefined` (no visual wheel,
169
+ * physics-only) if `display` wasn't specified at all, or there's no visual scene to build one
170
+ * against.
171
+ * @param world - The world instance
172
+ * @param wheelSettings - The wheel's own settings, already merged over whatever it inherits
173
+ * from `wheelBase.shared`/`sharedWheelOptions`
174
+ * @returns The resolved display options, or `undefined`
175
+ */
176
+ resolveWheelDisplay(world, wheelSettings) {
177
+ var _a, _b;
178
+ if (!wheelSettings.display || !world.visualScene) {
179
+ return undefined;
180
+ }
181
+ const { tyreRadius = defaultWheelDisplaySize.tyreRadius, tyreWidth = defaultWheelDisplaySize.tyreWidth } = wheelSettings;
182
+ return {
183
+ displayObject: world.visualScene.factory.createCylinder(tyreRadius, tyreWidth, (_a = wheelSettings.display.material) !== null && _a !== void 0 ? _a : {}),
184
+ wheelObjectDirection: (_b = wheelSettings.display.wheelObjectDirection) !== null && _b !== void 0 ? _b : 'x',
185
+ };
186
+ }
187
+ /**
188
+ * Create a `"GgCar"` entity: a box chassis rigid body (+ optional matching display box) wrapped
189
+ * in a full `GgCarEntity`, with each wheel's optional visual mesh built from its settings (see
190
+ * {@link resolveWheelDisplay}) rather than referencing an existing display object component,
191
+ * which a level JSON has no way to do.
192
+ * @param world - The world instance
193
+ * @param settings - The car settings
194
+ * @returns The created car entity
195
+ */
196
+ createGgCar(world, settings) {
197
+ var _a, _b, _c;
198
+ if (!world.physicsWorld) {
199
+ return undefined;
200
+ }
201
+ const { position, rotation, chassis, wheelBase, wheelOptions, sharedWheelOptions } = settings, rest = __rest(settings, ["position", "rotation", "chassis", "wheelBase", "wheelOptions", "sharedWheelOptions"]);
202
+ if (!(chassis === null || chassis === void 0 ? void 0 : chassis.dimensions)) {
203
+ throw new Error('Chassis dimensions are required for GgCar class');
204
+ }
205
+ if (!wheelBase && !wheelOptions) {
206
+ throw new Error('Either "wheelBase" or "wheelOptions" is required for GgCar class');
207
+ }
208
+ const chassisBody = world.physicsWorld.factory.createRigidBody({
209
+ shape: { shape: 'BOX', dimensions: chassis.dimensions },
210
+ body: Object.assign(Object.assign({}, defaultCarChassisBodyOptions), chassis.body),
211
+ });
212
+ const chassis3D = (_c = (_a = world.visualScene) === null || _a === void 0 ? void 0 : _a.factory.createBox(chassis.dimensions, (_b = chassis.material) !== null && _b !== void 0 ? _b : {})) !== null && _c !== void 0 ? _c : null;
213
+ const carProperties = wheelBase
214
+ ? Object.assign(Object.assign({}, rest), { wheelBase: {
215
+ shared: Object.assign(Object.assign({}, wheelBase.shared), { display: undefined }),
216
+ front: Object.assign(Object.assign({}, wheelBase.front), { display: this.resolveWheelDisplay(world, Object.assign(Object.assign({}, wheelBase.shared), wheelBase.front)) }),
217
+ rear: Object.assign(Object.assign({}, wheelBase.rear), { display: this.resolveWheelDisplay(world, Object.assign(Object.assign({}, wheelBase.shared), wheelBase.rear)) }),
218
+ } }) : Object.assign(Object.assign({}, rest), { wheelOptions: wheelOptions.map(wheel => (Object.assign(Object.assign({}, wheel), { display: this.resolveWheelDisplay(world, Object.assign(Object.assign({}, sharedWheelOptions), wheel)) }))), sharedWheelOptions: sharedWheelOptions && Object.assign(Object.assign({}, sharedWheelOptions), { display: undefined }) });
219
+ const entity = new GgCarEntity(carProperties, chassis3D, world.physicsWorld.factory.createRaycastVehicle(chassisBody));
220
+ if (position) {
221
+ entity.position = position;
222
+ }
223
+ if (rotation) {
224
+ entity.rotation = rotation;
225
+ }
226
+ return entity;
227
+ }
228
+ /**
229
+ * Create a `"MapGraph"` entity: a `MapGraph` built from plain node data (a flat/looped path or
230
+ * a rectangular grid, see {@link MapGraph3DSettings}), wrapped in a ready-to-use
231
+ * `MapGraph3dEntity`. The app still has to drive `loaderCursor$` itself once the level is
232
+ * loaded - see `gg-engine-level-json`'s "MapGraph" section.
233
+ * @param world - The world instance
234
+ * @param settings - The map graph settings
235
+ * @returns The created map graph entity
236
+ */
237
+ createMapGraph(world, settings) {
238
+ var _a, _b, _c;
239
+ const { graph, loadDepth, inertia, maxNodesLoadingPerTick, loadRateLimit } = settings;
240
+ if (!graph) {
241
+ throw new Error('"graph" is required for MapGraph class');
242
+ }
243
+ const normalizeNode = (node) => {
244
+ var _a;
245
+ return (Object.assign(Object.assign({}, node), { loadOptions: (_a = node.loadOptions) !== null && _a !== void 0 ? _a : {} }));
246
+ };
247
+ let mapGraph;
248
+ if (graph.type === 'grid') {
249
+ if (!((_a = graph.grid) === null || _a === void 0 ? void 0 : _a.length)) {
250
+ throw new Error('"graph.grid" must be a non-empty grid for MapGraph class');
251
+ }
252
+ mapGraph = MapGraph.fromMapSquareGrid(graph.grid.map(row => row.map(normalizeNode)));
253
+ }
254
+ else {
255
+ if (!((_b = graph.nodes) === null || _b === void 0 ? void 0 : _b.length)) {
256
+ throw new Error('"graph.nodes" must be a non-empty array for MapGraph class');
257
+ }
258
+ mapGraph = MapGraph.fromMapArray(graph.nodes.map(normalizeNode), (_c = graph.closed) !== null && _c !== void 0 ? _c : false);
259
+ }
260
+ const options = Object.assign(Object.assign(Object.assign({}, (loadDepth !== undefined ? { loadDepth } : {})), (inertia !== undefined ? { inertia } : {})), (maxNodesLoadingPerTick !== undefined ? { maxNodesLoadingPerTick } : {}));
261
+ const entity = new MapGraph3dEntity(mapGraph, options);
262
+ if (loadRateLimit !== undefined) {
263
+ entity.loadRateLimit = loadRateLimit;
264
+ }
265
+ return entity;
266
+ }
267
+ }
@@ -1,7 +1,8 @@
1
- import { Gg3dWorld, PhysicsTypeDocRepo3D, VisualTypeDocRepo3D } from './gg-3d-world';
1
+ import { Gg3dWorld, Gg3dWorldTypeDocRepo } from './gg-3d-world';
2
2
  import { GgMeta } from './models/gg-meta';
3
3
  import { Entity3d } from './entities/entity-3d';
4
4
  import { Point3, Point4 } from '../base';
5
+ import { Gg3dLevelLoader } from './level-loader';
5
6
  export declare enum CachingStrategy {
6
7
  Nothing = 0,
7
8
  Files = 1,
@@ -14,26 +15,66 @@ export type LoadOptions = {
14
15
  loadProps: boolean;
15
16
  propsPath?: string;
16
17
  };
17
- export type LoadResourcesResult<VTypeDoc extends VisualTypeDocRepo3D = VisualTypeDocRepo3D, PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> = {
18
+ export type LoadResourcesResult<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> = {
18
19
  resources: {
19
- object3D: VTypeDoc['displayObject'] | null;
20
- body: PTypeDoc['rigidBody'] | null;
20
+ object3D: TypeDoc['vTypeDoc']['displayObject'] | null;
21
+ body: TypeDoc['pTypeDoc']['rigidBody'] | null;
21
22
  }[];
22
23
  meta: GgMeta;
23
24
  };
24
- export type LoadResult<VTypeDoc extends VisualTypeDocRepo3D = VisualTypeDocRepo3D, PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> = {
25
- entities: Entity3d<VTypeDoc, PTypeDoc>[];
25
+ export type LoadResult<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> = {
26
+ entities: Entity3d<TypeDoc>[];
26
27
  meta: GgMeta;
27
28
  };
28
- export type LoadResultWithProps<VTypeDoc extends VisualTypeDocRepo3D = VisualTypeDocRepo3D, PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> = LoadResult<VTypeDoc, PTypeDoc> & {
29
- props?: LoadResult<VTypeDoc, PTypeDoc>[];
29
+ export type LoadResultWithProps<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> = LoadResult<TypeDoc> & {
30
+ props?: LoadResult<TypeDoc>[];
30
31
  };
31
- export declare class Gg3dLoader<VTypeDoc extends VisualTypeDocRepo3D = VisualTypeDocRepo3D, PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> {
32
- protected readonly world: Gg3dWorld;
32
+ /**
33
+ * Settings for the built-in `"Glb"` level entity class (3D only): loads a GG GLB+meta pair via
34
+ * `Gg3dLoader.loadGgGlb` and returns every entity it produces (the model itself, plus any nested
35
+ * props/scenes) grouped under one `GroupEntity`.
36
+ */
37
+ export interface Glb3DSettings {
38
+ /**
39
+ * Path (URL or path prefix, without extension) to the `.glb`/`.meta` pair - passed straight
40
+ * through to `loadGgGlb`
41
+ */
42
+ path: string;
43
+ /**
44
+ * Position of the loaded model
45
+ */
46
+ position?: Point3;
47
+ /**
48
+ * Rotation of the loaded model
49
+ */
50
+ rotation?: Point4;
51
+ /**
52
+ * Caching strategy, see `CachingStrategy`. Defaults to `CachingStrategy.Nothing`, same as
53
+ * `loadGgGlb` itself.
54
+ */
55
+ cachingStrategy?: CachingStrategy;
56
+ /**
57
+ * Whether to also load dummies flagged as props/scenes. Defaults to `true`, same as `loadGgGlb`.
58
+ */
59
+ loadProps?: boolean;
60
+ /**
61
+ * Path where to find prop scenes, if different from `path`'s own directory
62
+ */
63
+ propsPath?: string;
64
+ }
65
+ /**
66
+ * Full 3D loader exposed as `Gg3dWorld.loader`: GLB+meta asset loading (`loadGgGlb` and friends)
67
+ * layered on top of `Gg3dLevelLoader`, so `registerClass`/`loadLevel`/`loadLevelFromUrl`/
68
+ * `getEntityByName` are all available directly on `world.loader`. Also registers a `"Glb"` level
69
+ * entity class (see `Glb3DSettings`) so a level JSON can place a GLB model declaratively, the same
70
+ * way it places primitives/triggers/cameras.
71
+ * @template TypeDoc - The type document repository
72
+ */
73
+ export declare class Gg3dLoader<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> extends Gg3dLevelLoader<TypeDoc> {
33
74
  readonly filesCache: Map<string, [ArrayBuffer, GgMeta] | Promise<[ArrayBuffer, GgMeta]>>;
34
- readonly loadResultCache: Map<string, LoadResourcesResult<VTypeDoc, PTypeDoc> | Promise<LoadResourcesResult<VTypeDoc, PTypeDoc>>>;
35
- constructor(world: Gg3dWorld);
75
+ readonly loadResultCache: Map<string, LoadResourcesResult<TypeDoc> | Promise<LoadResourcesResult<TypeDoc>>>;
76
+ constructor(world: Gg3dWorld<TypeDoc>);
36
77
  loadGgGlbFiles(path: string, useCache?: boolean): Promise<[ArrayBuffer, GgMeta]>;
37
- loadGgGlbResources(path: string, cachingStrategy?: CachingStrategy): Promise<LoadResourcesResult<VTypeDoc, PTypeDoc>>;
38
- loadGgGlb(path: string, options?: Partial<LoadOptions>): Promise<LoadResultWithProps<VTypeDoc, PTypeDoc>>;
78
+ loadGgGlbResources(path: string, cachingStrategy?: CachingStrategy): Promise<LoadResourcesResult<TypeDoc>>;
79
+ loadGgGlb(path: string, options?: Partial<LoadOptions>): Promise<LoadResultWithProps<TypeDoc>>;
39
80
  }