@needle-tools/engine 3.0.0-alpha → 3.0.0-alpha.1
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.
- package/dist/needle-engine.js +11174 -11283
- package/dist/needle-engine.umd.cjs +230 -230
- package/lib/engine/engine_assetdatabase.js +24 -17
- package/lib/engine/engine_assetdatabase.js.map +1 -1
- package/lib/engine/engine_patcher.d.ts +4 -3
- package/lib/engine/engine_patcher.js +61 -44
- package/lib/engine/engine_patcher.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/engine_assetdatabase.ts +29 -18
- package/src/engine/engine_patcher.ts +104 -47
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "3.0.0-alpha",
|
|
3
|
+
"version": "3.0.0-alpha.1",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally.",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"module": "lib/needle-engine.js",
|
|
@@ -278,27 +278,21 @@ function updateUsers(symbol: symbol, user: object, object: object | object[], ad
|
|
|
278
278
|
|
|
279
279
|
// We dont want to update users during rendering
|
|
280
280
|
|
|
281
|
-
const $renderMethod = Symbol("render-method");
|
|
282
|
-
|
|
283
|
-
Object.defineProperty(WebGLRenderer.prototype, "render", {
|
|
284
|
-
set: function (this: WebGLRenderer, value: Function) {
|
|
285
|
-
this[$renderMethod] = wrapMethod(value);
|
|
286
|
-
},
|
|
287
|
-
get: function (this: WebGLRenderer) {
|
|
288
|
-
return this[$renderMethod];
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
281
|
|
|
282
|
+
try {
|
|
292
283
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
284
|
+
// addPatch(WebGLRenderer.prototype, "render",
|
|
285
|
+
// () => {
|
|
286
|
+
// noUpdateScope++;
|
|
287
|
+
// },
|
|
288
|
+
// () => {
|
|
289
|
+
// noUpdateScope--;
|
|
290
|
+
// }
|
|
291
|
+
// );
|
|
292
|
+
}
|
|
293
|
+
catch (e) {
|
|
294
|
+
console.warn("Could not wrap WebGLRenderer.render", e);
|
|
300
295
|
}
|
|
301
|
-
|
|
302
296
|
|
|
303
297
|
|
|
304
298
|
// addGltfLoadEventListener(GltfLoadEventType.BeforeLoad, (_) => {
|
|
@@ -320,3 +314,20 @@ function wrapMethod(fn: Function) {
|
|
|
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);
|
|
@@ -3,67 +3,102 @@
|
|
|
3
3
|
|
|
4
4
|
const _wrappedMethods = new WeakSet();
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
export
|
|
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;
|
|
8
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) {
|
|
48
|
+
|
|
49
|
+
// TODO
|
|
50
|
+
return;
|
|
14
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
|
-
}
|
|
51
|
-
else if (prototype.hasOwnProperty(backingField)) {
|
|
52
64
|
}
|
|
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 @@ export function removePatch(prototype: object, fieldName: string, cb: Function)
|
|
|
76
111
|
}
|
|
77
112
|
|
|
78
113
|
|
|
114
|
+
export const NeedlePatchesKey = "Needle:Patches";
|
|
79
115
|
|
|
80
|
-
|
|
81
|
-
|
|
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
|
+
}
|
|
82
126
|
|
|
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
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function executePrefixes(prototype, fieldName: string, instance: object, ...args) {
|
|
153
|
+
if (!instance) return;
|
|
154
|
+
const patches = getPatches(prototype, fieldName);
|
|
155
|
+
if (patches) {
|
|
156
|
+
for (const patchInfo of patches) {
|
|
157
|
+
patchInfo.prefix?.call(instance, ...args);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
103
160
|
}
|
|
104
161
|
|
|
105
|
-
function
|
|
162
|
+
function executePostFixes(prototype, fieldName: string, instance: object, result: any, ...args) {
|
|
106
163
|
if (!instance) return;
|
|
107
164
|
const patches = getPatches(prototype, fieldName);
|
|
108
165
|
if (patches) {
|
|
109
|
-
for (const
|
|
110
|
-
|
|
166
|
+
for (const patchInfo of patches) {
|
|
167
|
+
patchInfo.postfix?.call(instance, result, ...args);
|
|
111
168
|
}
|
|
112
169
|
}
|
|
113
170
|
}
|