@@ -1,65 +0,0 @@
|
|
1
|
-
import generateBMFont from 'msdf-bmfont-xml';
|
2
|
-
import fs from 'fs';
|
3
|
-
import path from 'path';
|
4
|
-
|
5
|
-
const args = process.argv;
|
6
|
-
|
7
|
-
const fontPath = args[2];
|
8
|
-
const outputDir = args[3];
|
9
|
-
const charsetPath = args.length > 4 ? args[4] : null;
|
10
|
-
|
11
|
-
if (!fontPath || !fs.existsSync(fontPath)) {
|
12
|
-
console.error("Missing font path. Please call this script with a path to a font file. Called with: \"" + fontPath + "\"");
|
13
|
-
process.exit(1);
|
14
|
-
}
|
15
|
-
if (!outputDir || !fs.existsSync(outputDir)) {
|
16
|
-
console.error("Missing output directory, please provide an output directory as the second argument. Called with: \"" + outputDir + "\"");
|
17
|
-
process.exit(1);
|
18
|
-
}
|
19
|
-
|
20
|
-
// https://soimy.github.io/msdf-bmfont-xml/#module-usage-examples
|
21
|
-
|
22
|
-
|
23
|
-
let message = "Generate font texture " + fontPath + " to " + outputDir;
|
24
|
-
|
25
|
-
let charset = null;
|
26
|
-
if (charsetPath && fs.existsSync(charsetPath)) {
|
27
|
-
message += " using chars from \"" + charsetPath + "\"";
|
28
|
-
charset = fs.readFileSync(charsetPath, 'utf8');
|
29
|
-
console.log("charset: ", charset);
|
30
|
-
if (charset.length <= 0) {
|
31
|
-
console.warn("WARN: Charset file is empty, using default charset");
|
32
|
-
charset = null;
|
33
|
-
}
|
34
|
-
}
|
35
|
-
|
36
|
-
console.log(message);
|
37
|
-
const opts = {
|
38
|
-
outputType: "json",
|
39
|
-
fieldType: "msdf",
|
40
|
-
textureSize: [4096, 4096],
|
41
|
-
smartSize: true, // shrink atlas to the smallest possible square
|
42
|
-
// rtl: true, // use RTL(Arabic/Persian) charators fix
|
43
|
-
};
|
44
|
-
if (charset?.length)
|
45
|
-
opts.charset = charset;
|
46
|
-
|
47
|
-
generateBMFont(fontPath, opts,
|
48
|
-
(error, textures, font) => {
|
49
|
-
if (error) throw error;
|
50
|
-
textures.forEach((texture, index) => {
|
51
|
-
const fileName = path.parse(texture.filename).name.toLocaleLowerCase() + ".png";
|
52
|
-
const outputPath = outputDir + "/" + fileName;
|
53
|
-
console.log("Write to", outputPath);
|
54
|
-
if (index > 0) console.log("WARN: Multiple font textures generated but they will override each other. You have currently " + charset?.length + " characters configured. Maybe too many?");
|
55
|
-
fs.writeFile(outputPath, texture.texture, (err) => {
|
56
|
-
if (err) throw err;
|
57
|
-
});
|
58
|
-
});
|
59
|
-
|
60
|
-
const fileName = path.parse(font.filename).name;
|
61
|
-
const name = outputDir + "/" + fileName.toLocaleLowerCase() + "-msdf.json";
|
62
|
-
fs.writeFile(name, font.data, (err) => {
|
63
|
-
if (err) throw err;
|
64
|
-
});
|
65
|
-
});
|
@@ -5,6 +5,7 @@
|
|
5
5
|
import { needleDrop } from "./drop.js";
|
6
6
|
import { editorConnection } from "./editor-connection.js";
|
7
7
|
import { needleCopyFiles } from "./copyfiles.js";
|
8
|
+
import { needleViteAlias } from "./alias.js";
|
8
9
|
|
9
10
|
export * from "./gzip.js";
|
10
11
|
export * from "./config.js";
|
@@ -18,6 +19,7 @@
|
|
18
19
|
// ensure we have user settings initialized with defaults
|
19
20
|
userSettings = { ...defaultUserSettings, ...userSettings }
|
20
21
|
const array = [
|
22
|
+
needleViteAlias(command, config, userSettings),
|
21
23
|
needleMeta(command, config, userSettings),
|
22
24
|
needlePoster(command),
|
23
25
|
needleReload(command, config, userSettings),
|
@@ -1,10 +1,11 @@
|
|
1
|
-
|
1
|
+
export * from "./engine_constants";
|
2
2
|
export { TypeStore } from "./engine_typestore";
|
3
3
|
export * from "./engine_context_registry";
|
4
4
|
export * from "./extensions/extensions"
|
5
5
|
export { InstancingUtil } from "./engine_instancing";
|
6
6
|
export * from "./engine_gameobject";
|
7
|
-
export * from "./engine_components"
|
7
|
+
export * from "./engine_components";
|
8
|
+
export * from "./engine_components_internal";
|
8
9
|
export { AssetReference } from "./engine_addressables";
|
9
10
|
export { Context, FrameEvent } from "./engine_setup";
|
10
11
|
export * from "./debug/debug";
|
@@ -163,7 +163,7 @@
|
|
163
163
|
}
|
164
164
|
else {
|
165
165
|
if (debug) console.log("Load async", this.uri);
|
166
|
-
this._loading = getLoader().loadSync(context, this._hashedUri,
|
166
|
+
this._loading = getLoader().loadSync(context, this._hashedUri, this.uri, null, prog => {
|
167
167
|
this.raiseProgressEvent(prog);
|
168
168
|
});
|
169
169
|
}
|
@@ -278,29 +278,23 @@
|
|
278
278
|
|
279
279
|
// We dont want to update users during rendering
|
280
280
|
|
281
|
-
const $renderMethod = Symbol("render-method");
|
282
281
|
|
283
|
-
|
284
|
-
set: function (this: WebGLRenderer, value: Function) {
|
285
|
-
this[$renderMethod] = wrapMethod(value);
|
286
|
-
},
|
287
|
-
get: function (this: WebGLRenderer) {
|
288
|
-
return this[$renderMethod];
|
289
|
-
}
|
290
|
-
});
|
282
|
+
try {
|
291
283
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
284
|
+
// addPatch(WebGLRenderer.prototype, "render",
|
285
|
+
// () => {
|
286
|
+
// noUpdateScope++;
|
287
|
+
// },
|
288
|
+
// () => {
|
289
|
+
// noUpdateScope--;
|
290
|
+
// }
|
291
|
+
// );
|
300
292
|
}
|
293
|
+
catch (e) {
|
294
|
+
console.warn("Could not wrap WebGLRenderer.render", e);
|
295
|
+
}
|
301
296
|
|
302
297
|
|
303
|
-
|
304
298
|
// addGltfLoadEventListener(GltfLoadEventType.BeforeLoad, (_) => {
|
305
299
|
// noUpdateScope++;
|
306
300
|
// });
|
@@ -320,3 +314,20 @@
|
|
320
314
|
// }
|
321
315
|
// });
|
322
316
|
|
317
|
+
|
318
|
+
|
319
|
+
|
320
|
+
|
321
|
+
// class MyObject {
|
322
|
+
// myNumber: number = 1;
|
323
|
+
// }
|
324
|
+
|
325
|
+
// addPatch(MyObject.prototype, "myNumber", (obj, oldValue, newValue) => {
|
326
|
+
// console.log("myNumber changed", oldValue, newValue);
|
327
|
+
// });
|
328
|
+
|
329
|
+
// const i = new MyObject();
|
330
|
+
// setInterval(() => {
|
331
|
+
// console.log("RUN");
|
332
|
+
// i.myNumber += 1;
|
333
|
+
// }, 1000);
|
@@ -1,30 +1,43 @@
|
|
1
1
|
import { IComponent } from "./engine_types";
|
2
|
+
import { getParam } from "./engine_utils";
|
2
3
|
|
3
|
-
|
4
|
-
const eventListeners = new Map<string, ((data: IComponent) => void)[]>();
|
5
|
-
|
6
4
|
export enum ComponentEvents {
|
7
5
|
Added = "component-added",
|
8
6
|
Removing = "removing-component"
|
9
7
|
}
|
10
8
|
|
11
|
-
|
12
|
-
if (!eventListeners.has(evt)) eventListeners.set(evt, []);
|
13
|
-
eventListeners.get(evt)?.push(cb);
|
14
|
-
}
|
9
|
+
const debug = getParam("debugcomponentevents");
|
15
10
|
|
16
|
-
export
|
17
|
-
const listeners = eventListeners.get(evt);
|
18
|
-
if (!listeners) return;
|
19
|
-
const index = listeners.indexOf(cb);
|
20
|
-
if (index < 0) return;
|
21
|
-
listeners.splice(index, 1);
|
22
|
-
}
|
11
|
+
export class ComponentLifecycleEvents {
|
23
12
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
13
|
+
private static eventListeners = new Map<string, ((data: IComponent) => void)[]>();
|
14
|
+
|
15
|
+
static addComponentLifecylceEventListener(evt: string, cb: (data: IComponent) => void) {
|
16
|
+
if (this.eventListeners.has(evt)) {
|
17
|
+
this.eventListeners.set(evt, []);
|
18
|
+
}
|
19
|
+
let arr = this.eventListeners.get(evt);
|
20
|
+
if (!arr) arr = [];
|
21
|
+
arr.push(cb);
|
22
|
+
this.eventListeners.set(evt, arr);
|
23
|
+
if(debug) console.log("Added event listener for " + evt, this.eventListeners)
|
29
24
|
}
|
30
|
-
|
25
|
+
|
26
|
+
static removeComponentLifecylceEventListener(evt: string, cb: (data: IComponent) => void) {
|
27
|
+
const listeners = this.eventListeners.get(evt);
|
28
|
+
if (!listeners) return;
|
29
|
+
const index = listeners.indexOf(cb);
|
30
|
+
if (index < 0) return;
|
31
|
+
listeners.splice(index, 1);
|
32
|
+
|
33
|
+
}
|
34
|
+
|
35
|
+
static dispatchComponentLifecycleEvent(evt: string, data: IComponent) {
|
36
|
+
const listeners = this.eventListeners.get(evt);
|
37
|
+
if(debug) console.log("Dispatching event " + evt, listeners)
|
38
|
+
if (!listeners) return;
|
39
|
+
for (const listener of listeners) {
|
40
|
+
listener(data);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
@@ -6,7 +6,7 @@
|
|
6
6
|
import { activeInHierarchyFieldName } from "./engine_constants";
|
7
7
|
import { apply } from "../engine-components/js-extensions/Object3D";
|
8
8
|
import { InstantiateIdProvider } from "./engine_networking_instantiate";
|
9
|
-
import { ComponentEvents,
|
9
|
+
import { ComponentEvents, ComponentLifecycleEvents } from "./engine_components_internal";
|
10
10
|
|
11
11
|
const debug = getParam("debuggetcomponent");
|
12
12
|
|
@@ -30,7 +30,7 @@
|
|
30
30
|
const index = go.userData.components.indexOf(componentInstance);
|
31
31
|
if (index < 0) return;
|
32
32
|
|
33
|
-
|
33
|
+
ComponentLifecycleEvents.dispatchComponentLifecycleEvent(ComponentEvents.Removing, componentInstance);
|
34
34
|
|
35
35
|
//@ts-ignore
|
36
36
|
componentInstance.gameObject = null;
|
@@ -66,7 +66,7 @@
|
|
66
66
|
updateActiveInHierarchyWithoutEventCall(obj);
|
67
67
|
componentInstance.__internalAwake();
|
68
68
|
}
|
69
|
-
|
69
|
+
ComponentLifecycleEvents.dispatchComponentLifecycleEvent(ComponentEvents.Added, componentInstance);
|
70
70
|
}
|
71
71
|
catch (err) {
|
72
72
|
console.error(err);
|
@@ -1,6 +1,5 @@
|
|
1
1
|
|
2
2
|
export const activeInHierarchyFieldName = Symbol("isActiveInHierarchy");
|
3
3
|
export const builtinComponentKeyName = "builtin_components";
|
4
|
-
|
5
|
-
|
6
|
-
export const $originalGuid = Symbol("originalGuid");
|
4
|
+
// It's easier to use a string than a symbol here because the symbol might not be the same when imported in other packages
|
5
|
+
export const editorGuidKeyName = "needle_editor_guid";
|
@@ -14,8 +14,14 @@
|
|
14
14
|
export type ContextCallback = (evt: ContextEventArgs) => void;
|
15
15
|
|
16
16
|
export class ContextRegistry {
|
17
|
-
static Current: IContext;
|
18
17
|
|
18
|
+
static get Current(): IContext{
|
19
|
+
return globalThis["NeedleEngine.Context.Current"]
|
20
|
+
}
|
21
|
+
static set Current(ctx: IContext) {
|
22
|
+
globalThis["NeedleEngine.Context.Current"] = ctx;
|
23
|
+
}
|
24
|
+
|
19
25
|
static Registered: IContext[] = [];
|
20
26
|
|
21
27
|
static register(ctx: IContext) {
|
@@ -87,15 +87,12 @@
|
|
87
87
|
|
88
88
|
export class Context implements IContext {
|
89
89
|
|
90
|
-
private static _current: Context;
|
91
|
-
|
92
90
|
static get Current(): Context {
|
93
|
-
return
|
91
|
+
return ContextRegistry.Current as Context;
|
94
92
|
}
|
95
93
|
|
96
94
|
static set Current(context: Context) {
|
97
95
|
ContextRegistry.Current = context;
|
98
|
-
this._current = context;
|
99
96
|
}
|
100
97
|
|
101
98
|
name: string;
|
@@ -516,10 +513,10 @@
|
|
516
513
|
if (!this.isManagedExternally)
|
517
514
|
this.domElement.prepend(this.renderer.domElement);
|
518
515
|
|
519
|
-
Context.
|
516
|
+
Context.Current = this;
|
520
517
|
|
521
518
|
// Setup
|
522
|
-
Context.
|
519
|
+
Context.Current = this;
|
523
520
|
for (let i = 0; i < this.new_scripts.length; i++) {
|
524
521
|
const script = this.new_scripts[i];
|
525
522
|
if (script.gameObject !== undefined && script.gameObject !== null) {
|
@@ -546,13 +543,13 @@
|
|
546
543
|
// resolve post setup callbacks (things that rely on threejs objects having references to components)
|
547
544
|
if (this.post_setup_callbacks) {
|
548
545
|
for (let i = 0; i < this.post_setup_callbacks.length; i++) {
|
549
|
-
Context.
|
546
|
+
Context.Current = this;
|
550
547
|
await this.post_setup_callbacks[i](this);
|
551
548
|
}
|
552
549
|
}
|
553
550
|
|
554
551
|
if (!this.mainCamera) {
|
555
|
-
Context.
|
552
|
+
Context.Current = this;
|
556
553
|
let camera: ICamera | null = null;
|
557
554
|
foreachComponent(this.scene, comp => {
|
558
555
|
const cam = comp as ICamera;
|
@@ -577,7 +574,7 @@
|
|
577
574
|
}
|
578
575
|
}
|
579
576
|
|
580
|
-
Context.
|
577
|
+
Context.Current = this;
|
581
578
|
looputils.processNewScripts(this);
|
582
579
|
|
583
580
|
// const mainCam = this.mainCameraComponent as Camera;
|
@@ -624,10 +621,10 @@
|
|
624
621
|
|
625
622
|
this._stats?.begin();
|
626
623
|
|
627
|
-
Context.
|
624
|
+
Context.Current = this;
|
628
625
|
if (this.onHandlePaused()) return;
|
629
626
|
|
630
|
-
Context.
|
627
|
+
Context.Current = this;
|
631
628
|
this.time.update();
|
632
629
|
if (debugframerate)
|
633
630
|
console.log("FPS", (this.time.smoothedFps).toFixed(0));
|
@@ -655,7 +652,7 @@
|
|
655
652
|
const script = this.scripts_earlyUpdate[i];
|
656
653
|
if (!script.activeAndEnabled) continue;
|
657
654
|
if (script.earlyUpdate !== undefined) {
|
658
|
-
Context.
|
655
|
+
Context.Current = this;
|
659
656
|
script.earlyUpdate();
|
660
657
|
}
|
661
658
|
}
|
@@ -668,7 +665,7 @@
|
|
668
665
|
const script = this.scripts_update[i];
|
669
666
|
if (!script.activeAndEnabled) continue;
|
670
667
|
if (script.update !== undefined) {
|
671
|
-
Context.
|
668
|
+
Context.Current = this;
|
672
669
|
script.update();
|
673
670
|
}
|
674
671
|
}
|
@@ -681,7 +678,7 @@
|
|
681
678
|
const script = this.scripts_lateUpdate[i];
|
682
679
|
if (!script.activeAndEnabled) continue;
|
683
680
|
if (script.lateUpdate !== undefined) {
|
684
|
-
Context.
|
681
|
+
Context.Current = this;
|
685
682
|
script.lateUpdate();
|
686
683
|
}
|
687
684
|
}
|
@@ -712,7 +709,7 @@
|
|
712
709
|
if (!script.activeAndEnabled) continue;
|
713
710
|
// if(script.isActiveAndEnabled === false) continue;
|
714
711
|
if (script.onBeforeRender !== undefined) {
|
715
|
-
Context.
|
712
|
+
Context.Current = this;
|
716
713
|
script.onBeforeRender(frame);
|
717
714
|
}
|
718
715
|
}
|
@@ -741,7 +738,7 @@
|
|
741
738
|
const script = this.scripts_onAfterRender[i];
|
742
739
|
if (!script.activeAndEnabled) continue;
|
743
740
|
if (script.onAfterRender !== undefined) {
|
744
|
-
Context.
|
741
|
+
Context.Current = this;
|
745
742
|
script.onAfterRender();
|
746
743
|
}
|
747
744
|
}
|
@@ -798,7 +795,7 @@
|
|
798
795
|
const script = this.scripts_pausedChanged[i];
|
799
796
|
if (!script.activeAndEnabled) continue;
|
800
797
|
if (script.onPausedChanged !== undefined) {
|
801
|
-
Context.
|
798
|
+
Context.Current = this;
|
802
799
|
script.onPausedChanged(paused, this._wasPaused);
|
803
800
|
}
|
804
801
|
}
|
@@ -240,7 +240,7 @@
|
|
240
240
|
totalProgress01: this._loadingProgress01
|
241
241
|
}
|
242
242
|
}
|
243
|
-
const res = await loader.loadSync(ctx, url,
|
243
|
+
const res = await loader.loadSync(ctx, url, url, hash, prog => {
|
244
244
|
// Calc progress
|
245
245
|
progress.progress = prog;
|
246
246
|
this._loadingProgress01 = calculateProgress01(progress);
|
@@ -10,8 +10,8 @@
|
|
10
10
|
import { activeInHierarchyFieldName } from "./engine_constants";
|
11
11
|
import { assign } from "./engine_serialization_core";
|
12
12
|
import { disposeObjectResources, __internalNotifyObjectDestroyed as __internalRemoveReferences } from "./engine_assetdatabase";
|
13
|
-
import {
|
14
|
-
import {
|
13
|
+
import { editorGuidKeyName } from "./engine_constants";
|
14
|
+
import { ComponentLifecycleEvents, ComponentEvents } from "./engine_components_internal";
|
15
15
|
|
16
16
|
const debug = getParam("debuggetcomponent");
|
17
17
|
const debugInstantiate = getParam("debuginstantiate");
|
@@ -373,13 +373,13 @@
|
|
373
373
|
const copy = new comp.constructor();
|
374
374
|
assign(copy, comp);
|
375
375
|
// make sure the original guid stays intact
|
376
|
-
if (comp[
|
377
|
-
copy[
|
376
|
+
if (comp[editorGuidKeyName] !== undefined)
|
377
|
+
copy[editorGuidKeyName] = comp[editorGuidKeyName];
|
378
378
|
newComponents.push(copy);
|
379
379
|
copy.gameObject = clone;
|
380
380
|
// copy.transform = clone;
|
381
381
|
componentsList.push(copy);
|
382
|
-
|
382
|
+
ComponentLifecycleEvents.dispatchComponentLifecycleEvent(ComponentEvents.Added, copy);
|
383
383
|
}
|
384
384
|
}
|
385
385
|
|
@@ -8,7 +8,7 @@
|
|
8
8
|
import { assign, ImplementationInformation, ISerializable, SerializationContext } from "./engine_serialization_core";
|
9
9
|
import { NEEDLE_components } from "./extensions/NEEDLE_components";
|
10
10
|
import { debugExtension } from "./engine_default_parameters";
|
11
|
-
import {
|
11
|
+
import { editorGuidKeyName, builtinComponentKeyName } from "./engine_constants";
|
12
12
|
import { GuidsMap, IComponent, IGameObject, SourceIdentifier } from "./engine_types";
|
13
13
|
import { UIDProvider } from "./engine_types";
|
14
14
|
import { addNewComponent } from "./engine_components";
|
@@ -174,7 +174,7 @@
|
|
174
174
|
|
175
175
|
// assign the guid of the original instance
|
176
176
|
if("guid" in compData)
|
177
|
-
instance[
|
177
|
+
instance[editorGuidKeyName] = compData.guid;
|
178
178
|
|
179
179
|
// Object.assign(instance, compData);
|
180
180
|
// dont call awake here because some references might not be resolved yet and components that access those fields in awake will throw
|
@@ -8,8 +8,8 @@
|
|
8
8
|
export interface INeedleGltfLoader {
|
9
9
|
createBuiltinComponents(context: Context, gltfId: SourceIdentifier, gltf, seed: number | null | UIDProvider, extension?: NEEDLE_components): Promise<void>
|
10
10
|
writeBuiltinComponentData(comp: object, context: SerializationContext);
|
11
|
-
parseSync(context: Context, data, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined>;
|
12
|
-
loadSync(context: Context, url: string, seed: number | UIDProvider | null,
|
11
|
+
parseSync(context: Context, data : string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined>;
|
12
|
+
loadSync(context: Context, url: string, sourceId:string, seed: number | UIDProvider | null, prog?: (prog : ProgressEvent) => void): Promise<GLTF | undefined>
|
13
13
|
}
|
14
14
|
|
15
15
|
let gltfLoader: INeedleGltfLoader;
|
@@ -48,13 +48,13 @@
|
|
48
48
|
if (name.endsWith(".gltf") || name.endsWith(".glb")) {
|
49
49
|
return new Promise((resolve, _reject) => {
|
50
50
|
const reader = new FileReader()
|
51
|
-
reader.
|
51
|
+
reader.readAsArrayBuffer(file);
|
52
52
|
reader.onloadend = async (_ev: ProgressEvent<FileReader>) => {
|
53
|
-
const content = reader.result as
|
53
|
+
const content = reader.result as ArrayBuffer;
|
54
54
|
// first load it locally
|
55
55
|
const seed = generateSeed();
|
56
56
|
const prov = new InstantiateIdProvider(seed);
|
57
|
-
const gltf: GLTF = await getLoader().
|
57
|
+
const gltf: GLTF = await getLoader().parseSync(context, content, file.name, prov) as GLTF;
|
58
58
|
if (gltf && gltf.scene) {
|
59
59
|
const obj = gltf.scene as unknown as IGameObject;
|
60
60
|
// if we dont have a guid yet (because components guids are actually created in a callback a bit later)
|
@@ -85,7 +85,8 @@
|
|
85
85
|
return new Promise(async (resolve, _reject) => {
|
86
86
|
const seed = generateSeed();
|
87
87
|
const prov = new InstantiateIdProvider(seed);
|
88
|
-
const
|
88
|
+
const urlStr = url.toString();
|
89
|
+
const gltf: GLTF = await getLoader().loadSync(context, urlStr, urlStr, prov) as GLTF;
|
89
90
|
if (gltf && gltf.scene) {
|
90
91
|
const obj = gltf.scene as unknown as IGameObject;
|
91
92
|
// handleUpload(context.connection, file, seed, obj); // TODO needs to upload the URL only and store that
|
@@ -3,67 +3,102 @@
|
|
3
3
|
|
4
4
|
const _wrappedMethods = new WeakSet();
|
5
5
|
|
6
|
-
export declare type FieldPatch = (instance: object, oldValue: any, newValue: any) => any;
|
7
|
-
export type MethodPatch<T> = (instance: T, result: any, ...args) => any;
|
8
6
|
|
7
|
+
// export function wrap<T>(prototype: object, methodName: string, before: (t: T) => void, after: (t: T) => void) {
|
8
|
+
|
9
|
+
// const $key = Symbol(methodName + "-patched");
|
10
|
+
|
11
|
+
// const alreadyDefined = Object.getOwnPropertyDescriptor(prototype, methodName);
|
12
|
+
// if (alreadyDefined) {
|
13
|
+
// const originalRender = alreadyDefined.get;
|
14
|
+
// if (originalRender) {
|
15
|
+
// // Object.defineProperty(prototype, "render", {
|
16
|
+
// // set: function (this: any, value: Function) {
|
17
|
+
// // originalRender.call(this);
|
18
|
+
// // },
|
19
|
+
// // get: function (this: ) {
|
20
|
+
// // return originalRender.call(this);
|
21
|
+
// // }
|
22
|
+
// // });
|
23
|
+
// }
|
24
|
+
// }
|
25
|
+
// else {
|
26
|
+
// Object.defineProperty(prototype, methodName, {
|
27
|
+
// set: function (this: any, value: Function) {
|
28
|
+
// this[$key] = value;
|
29
|
+
// },
|
30
|
+
// get: function (this: any) {
|
31
|
+
// return this[$key];
|
32
|
+
// }
|
33
|
+
// });
|
34
|
+
// }
|
35
|
+
// }
|
36
|
+
|
37
|
+
|
38
|
+
// export declare type FieldPatch = (instance: object, oldValue: any, newValue: any) => any;
|
39
|
+
|
40
|
+
export type Prefix = (...args) => any;
|
41
|
+
export type Postfix = (...args) => any;
|
42
|
+
|
9
43
|
/**
|
10
44
|
* Use patcher for patching properties insteadof calling Object.defineProperty individually
|
11
45
|
* since this will cause conflicts if multiple patches need to be applied to the same property
|
12
46
|
*/
|
13
|
-
export function addPatch<
|
47
|
+
export function addPatch<T extends object>(prototype: T, fieldName: string, beforeCallback?: Prefix, afterCallback?: Postfix) {
|
14
48
|
|
49
|
+
// TODO
|
50
|
+
return;
|
51
|
+
|
15
52
|
// TODO: we probably want to turn this into a symbol to prevent anyone from overriding it
|
16
53
|
// But when we need to store the symbol per prototype to allow e.g. material disposing to iterate those and dispose all
|
17
|
-
const backingField = fieldName + "__needle";// Symbol(fieldName);// + " (patched)";
|
54
|
+
const backingField = Symbol(fieldName + "__needle");// Symbol(fieldName);// + " (patched)";
|
18
55
|
|
19
|
-
internalAddPatch(prototype, fieldName,
|
56
|
+
internalAddPatch(prototype, fieldName, afterCallback, beforeCallback);
|
20
57
|
|
21
58
|
const desc = Object.getOwnPropertyDescriptor(prototype, fieldName);
|
59
|
+
|
60
|
+
const existing = prototype[fieldName];
|
61
|
+
console.log(prototype);
|
22
62
|
|
23
63
|
if (desc) {
|
24
|
-
// TODO: check if the property is writable
|
25
|
-
// the property might be a method in which case we want to wrap it
|
26
|
-
if (typeof desc.value === "function") {
|
27
|
-
const method = desc.value;
|
28
|
-
if (method) {
|
29
|
-
if (_wrappedMethods.has(method)) {
|
30
|
-
return;
|
31
|
-
}
|
32
|
-
_wrappedMethods.add(method);
|
33
|
-
prototype[fieldName] = function (this: object, ...args: any[]) {
|
34
|
-
// call the original method
|
35
|
-
const result = method.apply(this, args);
|
36
|
-
// call the patches
|
37
|
-
const patches = getPatches(prototype, fieldName);
|
38
|
-
if (patches) {
|
39
|
-
for (const patch of patches) {
|
40
|
-
patch(this, result, ...args);
|
41
|
-
}
|
42
|
-
}
|
43
|
-
return result;
|
44
|
-
}
|
45
|
-
}
|
46
|
-
else {
|
47
|
-
// TODO: declare method?
|
48
|
-
}
|
49
|
-
}
|
50
64
|
}
|
51
|
-
else if (prototype.hasOwnProperty(backingField)) {
|
52
|
-
}
|
53
65
|
else {
|
54
66
|
Object.defineProperty(prototype, fieldName, {
|
55
67
|
set: function (this: object, value: any) {
|
56
|
-
|
57
|
-
|
58
|
-
|
68
|
+
console.log("setting", fieldName, value);
|
69
|
+
if (typeof value === "function") {
|
70
|
+
this[backingField] = addWrapper(value, prototype, fieldName);
|
71
|
+
}
|
72
|
+
else {
|
73
|
+
const prev = this[backingField];
|
74
|
+
executePrefixes(prototype, fieldName, this, prev, value);
|
75
|
+
this[backingField] = value;
|
76
|
+
executePostFixes(prototype, fieldName, this, prev, value);
|
77
|
+
}
|
59
78
|
},
|
60
79
|
get: function (this: any) {
|
61
|
-
|
80
|
+
console.log("GET", fieldName);
|
81
|
+
const value = this[backingField];
|
82
|
+
if (typeof value === "function") {
|
83
|
+
if (value[backingField]) {
|
84
|
+
return value[backingField];
|
85
|
+
}
|
86
|
+
}
|
87
|
+
return value;
|
62
88
|
}
|
63
89
|
});
|
64
90
|
}
|
65
91
|
}
|
66
92
|
|
93
|
+
function addWrapper(originalFunction: Function, prototype, fieldname) {
|
94
|
+
return function (this: object, ...args: any[]) {
|
95
|
+
executePrefixes(prototype, fieldname, this, ...args);
|
96
|
+
const result = originalFunction.apply(this, args);
|
97
|
+
executePostFixes(prototype, fieldname, this, result, ...args);
|
98
|
+
return result;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
67
102
|
export function removePatch(prototype: object, fieldName: string, cb: Function) {
|
68
103
|
const patches = getPatches(prototype, fieldName);
|
69
104
|
if (patches) {
|
@@ -76,38 +111,60 @@
|
|
76
111
|
}
|
77
112
|
|
78
113
|
|
114
|
+
export const NeedlePatchesKey = "Needle:Patches";
|
79
115
|
|
116
|
+
declare type PatchInfo = {
|
117
|
+
prefix?: Prefix;
|
118
|
+
postfix?: Postfix;
|
119
|
+
}
|
120
|
+
function patches(): WeakMap<object, Map<string, PatchInfo[]>> {
|
121
|
+
if (!globalThis[NeedlePatchesKey]) {
|
122
|
+
globalThis[NeedlePatchesKey] = new WeakMap<object, Map<string, PatchInfo[]>>();
|
123
|
+
}
|
124
|
+
return globalThis[NeedlePatchesKey];
|
125
|
+
}
|
80
126
|
|
81
|
-
const patches = new WeakMap<object, Map<string, Function[]>>();
|
82
|
-
|
83
127
|
function getPatches(prototype, fieldName: string) {
|
84
|
-
let patchesMap = patches.get(prototype);
|
128
|
+
let patchesMap = patches().get(prototype);
|
85
129
|
if (!patchesMap) {
|
86
130
|
return null;
|
87
131
|
}
|
88
132
|
return patchesMap.get(fieldName);;
|
89
133
|
}
|
90
134
|
|
91
|
-
function internalAddPatch(prototype, fieldName: string,
|
92
|
-
let patchesMap = patches.get(prototype);
|
135
|
+
function internalAddPatch(prototype, fieldName: string, postfix?: Postfix, prefix?: Prefix) {
|
136
|
+
let patchesMap = patches().get(prototype);
|
93
137
|
if (!patchesMap) {
|
94
138
|
patchesMap = new Map();
|
95
|
-
patches.set(prototype, patchesMap);
|
139
|
+
patches().set(prototype, patchesMap);
|
96
140
|
}
|
97
141
|
let patchList = patchesMap.get(fieldName);
|
98
142
|
if (!patchList) {
|
99
143
|
patchList = [];
|
100
144
|
patchesMap.set(fieldName, patchList);
|
101
145
|
}
|
102
|
-
patchList.push(
|
146
|
+
patchList.push({
|
147
|
+
prefix: prefix,
|
148
|
+
postfix: postfix
|
149
|
+
});
|
103
150
|
}
|
104
151
|
|
105
|
-
function
|
152
|
+
function executePrefixes(prototype, fieldName: string, instance: object, ...args) {
|
106
153
|
if (!instance) return;
|
107
154
|
const patches = getPatches(prototype, fieldName);
|
108
155
|
if (patches) {
|
109
|
-
for (const
|
110
|
-
|
156
|
+
for (const patchInfo of patches) {
|
157
|
+
patchInfo.prefix?.call(instance, ...args);
|
111
158
|
}
|
112
159
|
}
|
160
|
+
}
|
161
|
+
|
162
|
+
function executePostFixes(prototype, fieldName: string, instance: object, result: any, ...args) {
|
163
|
+
if (!instance) return;
|
164
|
+
const patches = getPatches(prototype, fieldName);
|
165
|
+
if (patches) {
|
166
|
+
for (const patchInfo of patches) {
|
167
|
+
patchInfo.postfix?.call(instance, result, ...args);
|
168
|
+
}
|
169
|
+
}
|
113
170
|
}
|
@@ -24,11 +24,11 @@
|
|
24
24
|
return writeBuiltinComponentData(comp, context);
|
25
25
|
}
|
26
26
|
|
27
|
-
parseSync(context: Context, data, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
|
27
|
+
parseSync(context: Context, data : string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
|
28
28
|
return parseSync(context, data, path, seed);
|
29
29
|
}
|
30
|
-
loadSync(context: Context, url: string, seed: number | UIDProvider | null,
|
31
|
-
return loadSync(context, url,
|
30
|
+
loadSync(context: Context, url: string, sourceId:string, seed: number | UIDProvider | null, prog?: ((ProgressEvent: any) => void) | undefined): Promise<GLTF | undefined> {
|
31
|
+
return loadSync(context, url, sourceId, seed, prog);
|
32
32
|
}
|
33
33
|
}
|
34
34
|
|
@@ -87,7 +87,7 @@
|
|
87
87
|
|
88
88
|
async function handleLoadedGltf(context: Context, gltfId: string, gltf, seed: number | null | UIDProvider, componentsExtension) {
|
89
89
|
if (printGltf)
|
90
|
-
console.
|
90
|
+
console.warn("glTF", gltfId, gltf);
|
91
91
|
await getLoader().createBuiltinComponents(context, gltfId, gltf, seed, componentsExtension);
|
92
92
|
|
93
93
|
// load and assign animation
|
@@ -102,7 +102,7 @@
|
|
102
102
|
return loader;
|
103
103
|
}
|
104
104
|
|
105
|
-
export function parseSync(context: Context, data, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
|
105
|
+
export function parseSync(context: Context, data : string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
|
106
106
|
if (typeof path !== "string") {
|
107
107
|
console.warn("Parse gltf binary without path, this might lead to errors in resolving extensions. Please provide the source path of the gltf/glb file", path, typeof path);
|
108
108
|
}
|
@@ -131,7 +131,7 @@
|
|
131
131
|
});
|
132
132
|
}
|
133
133
|
|
134
|
-
export function loadSync(context: Context, url: string, seed: number | UIDProvider | null,
|
134
|
+
export function loadSync(context: Context, url: string, sourceId:string, seed: number | UIDProvider | null, prog?: (ProgressEvent) => void): Promise<GLTF | undefined> {
|
135
135
|
// better to create new loaders every time
|
136
136
|
// (maybe we can cache them...)
|
137
137
|
// but due to the async nature and potentially triggering multiple loads at the same time
|
@@ -145,7 +145,7 @@
|
|
145
145
|
invokeEvents(GltfLoadEventType.BeforeLoad, new GltfLoadEvent(context, url, loader));
|
146
146
|
loader.load(url, async data => {
|
147
147
|
invokeEvents(GltfLoadEventType.AfterLoaded, new GltfLoadEvent(context, url, loader, data));
|
148
|
-
await handleLoadedGltf(context,
|
148
|
+
await handleLoadedGltf(context, sourceId, data, seed, componentsExtension);
|
149
149
|
invokeEvents(GltfLoadEventType.FinishedSetup, new GltfLoadEvent(context, url, loader, data));
|
150
150
|
registerPrewarmObject(data.scene, context);
|
151
151
|
resolve(data);
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import { Clock } from 'three'
|
2
2
|
import { getParam } from './engine_utils';
|
3
|
+
import { ITime } from './engine_types';
|
3
4
|
|
4
5
|
const timescaleUrl = getParam("timescale");
|
5
6
|
let timeScale = 1;
|
6
7
|
if (typeof timescaleUrl === "number") timeScale = timescaleUrl;
|
7
8
|
|
8
|
-
export class Time {
|
9
|
+
export class Time implements ITime {
|
9
10
|
|
10
11
|
deltaTime = 0;
|
11
12
|
time = 0;
|
@@ -27,9 +27,13 @@
|
|
27
27
|
chained?: Array<Generator>
|
28
28
|
}
|
29
29
|
|
30
|
+
export interface ITime {
|
31
|
+
get time(): number;
|
32
|
+
}
|
30
33
|
|
31
34
|
export interface IContext {
|
32
35
|
alias?: string | null;
|
36
|
+
hash?:string;
|
33
37
|
|
34
38
|
scene: Scene;
|
35
39
|
renderer: WebGLRenderer;
|
@@ -37,6 +41,8 @@
|
|
37
41
|
mainCameraComponent: ICamera | undefined;
|
38
42
|
domElement: HTMLElement;
|
39
43
|
|
44
|
+
time: ITime;
|
45
|
+
|
40
46
|
scripts: IComponent[];
|
41
47
|
scripts_pausedChanged: IComponent[];
|
42
48
|
// scripts with update event
|
@@ -466,7 +466,7 @@
|
|
466
466
|
}
|
467
467
|
|
468
468
|
private setFont(opts: any, fontStyle: FontStyle) {
|
469
|
-
const name = this.
|
469
|
+
const name = this.getFontStyleName(fontStyle);
|
470
470
|
let family = name;
|
471
471
|
if (!family?.endsWith("-msdf.json")) family += "-msdf.json";
|
472
472
|
opts.fontFamily = family;
|
@@ -476,23 +476,47 @@
|
|
476
476
|
opts.fontTexture = texture;
|
477
477
|
}
|
478
478
|
|
479
|
-
private
|
479
|
+
private getFontStyleName(style: FontStyle): string | null {
|
480
480
|
if (!this.font) return null;
|
481
|
-
|
482
|
-
|
483
|
-
//
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
481
|
+
let fontName = this.font;
|
482
|
+
|
483
|
+
// if a font path has a known suffix we remove it
|
484
|
+
if (fontName.endsWith("-regular")) {
|
485
|
+
if (style === FontStyle.Normal) return getPath(this.sourceId, fontName);
|
486
|
+
fontName = fontName.substring(0, fontName.length - "-regular".length);
|
487
|
+
}
|
488
|
+
else if (fontName.endsWith("-bold")) {
|
489
|
+
if (style === FontStyle.Bold)return getPath(this.sourceId, fontName);
|
490
|
+
fontName = fontName.substring(0, fontName.length - "-bold".length);
|
491
|
+
}
|
492
|
+
else if (fontName.endsWith("-italic")) {
|
493
|
+
if (style === FontStyle.Italic)return getPath(this.sourceId, fontName);
|
494
|
+
fontName = fontName.substring(0, fontName.length - "-italic".length);
|
495
|
+
}
|
496
|
+
else if (fontName.endsWith("-bolditalic")) {
|
497
|
+
if (style === FontStyle.BoldAndItalic)return getPath(this.sourceId, fontName);
|
498
|
+
fontName = fontName.substring(0, fontName.length - "-bolditalic".length);
|
499
|
+
}
|
500
|
+
else
|
501
|
+
// If a font does not have a specific style suffic we dont support getting the correct font style
|
502
|
+
return getPath(this.sourceId, fontName);
|
503
|
+
|
504
|
+
switch (style) {
|
505
|
+
case FontStyle.Normal:
|
506
|
+
fontName += "-regular";
|
507
|
+
break;
|
508
|
+
case FontStyle.Bold:
|
509
|
+
fontName += "-bold";
|
510
|
+
break;
|
511
|
+
case FontStyle.Italic:
|
512
|
+
fontName += "-italic";
|
513
|
+
break;
|
514
|
+
case FontStyle.BoldAndItalic:
|
515
|
+
fontName += "-bolditalic";
|
516
|
+
break;
|
517
|
+
}
|
518
|
+
|
519
|
+
return getPath(this.sourceId, fontName);
|
496
520
|
}
|
497
521
|
}
|
498
522
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import { existsSync } from 'fs';
|
2
|
+
import path from 'path';
|
3
|
+
|
4
|
+
const projectDir = process.cwd() + "/";
|
5
|
+
|
6
|
+
const packages_to_resolve = {
|
7
|
+
'three': {},
|
8
|
+
'@needle-tools/engine': {},
|
9
|
+
'peerjs': {},
|
10
|
+
'websocket-ts': {},
|
11
|
+
'md5': {},
|
12
|
+
}
|
13
|
+
|
14
|
+
export const needleViteAlias = (command, config, userSettings) => {
|
15
|
+
|
16
|
+
if (config?.noAlias === true || userSettings?.noAlias === true)
|
17
|
+
return;
|
18
|
+
|
19
|
+
return {
|
20
|
+
name: "needle-alias",
|
21
|
+
config(config) {
|
22
|
+
setTimeout(() => {
|
23
|
+
console.log('[needle-alias] ProjectDirectory: ' + projectDir);
|
24
|
+
}, 150);
|
25
|
+
|
26
|
+
if (!config.resolve) config.resolve = {};
|
27
|
+
if (!config.resolve.alias) config.resolve.alias = {};
|
28
|
+
const aliasDict = config.resolve.alias;
|
29
|
+
for (const name in packages_to_resolve) {
|
30
|
+
if (!aliasDict[name]) {
|
31
|
+
addPathResolver(name, aliasDict);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
function addPathResolver(name, aliasList) {
|
38
|
+
// If a package at the node_modules path exist we resolve the request there
|
39
|
+
// introduced in 89a50718c38940abb99ee16c5e029065e41d7d65
|
40
|
+
const res = path.resolve(projectDir, 'node_modules', name);
|
41
|
+
if (existsSync(res)) {
|
42
|
+
aliasList[name] = () => res;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
};
|