@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/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
- function wrapMethod(fn: Function) {
294
- return function (this: WebGLRenderer, ...args) {
295
- noUpdateScope++;
296
- const result = fn.apply(this, args);
297
- noUpdateScope--;
298
- return result;
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
- export declare type FieldPatch = (instance: object, oldValue: any, newValue: any) => any;
7
- export type MethodPatch<T> = (instance: T, result: any, ...args) => any;
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<TType extends object, TCallback extends (FieldPatch | MethodPatch<any>)>(prototype: TType, fieldName: string, cb: TCallback) {
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, cb);
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
- const prev = this[backingField];
57
- this[backingField] = value;
58
- executePatches(prototype, fieldName, this, prev, value);
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
- return this[backingField];
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
- const patches = new WeakMap<object, Map<string, Function[]>>();
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, cb: Function) {
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(cb);
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 executePatches(prototype, fieldName: string, instance: object, oldValue: any, newValue: any) {
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 patch of patches) {
110
- patch(instance, oldValue, newValue);
166
+ for (const patchInfo of patches) {
167
+ patchInfo.postfix?.call(instance, result, ...args);
111
168
  }
112
169
  }
113
170
  }