@needle-tools/engine 4.1.0-beta.6 → 4.1.0-beta.8
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/CHANGELOG.md +6 -0
- package/dist/needle-engine.bundle.js +1168 -1170
- package/dist/needle-engine.bundle.light.js +1303 -1305
- package/dist/needle-engine.bundle.light.min.js +54 -54
- package/dist/needle-engine.bundle.light.umd.cjs +91 -91
- package/dist/needle-engine.bundle.min.js +60 -60
- package/dist/needle-engine.bundle.umd.cjs +60 -60
- package/dist/vendor.js +174 -174
- package/dist/vendor.light.js +174 -174
- package/dist/vendor.light.min.js +12 -12
- package/dist/vendor.light.umd.cjs +13 -13
- package/dist/vendor.min.js +12 -12
- package/dist/vendor.umd.cjs +13 -13
- package/lib/engine/engine_addressables.d.ts +6 -4
- package/lib/engine/engine_addressables.js +8 -1
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_context.js +2 -0
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_gameobject.d.ts +2 -0
- package/lib/engine/engine_gameobject.js +5 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_input.d.ts +19 -6
- package/lib/engine/engine_input.js +0 -10
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_license.js +1 -1
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_networking_instantiate.d.ts +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +8 -2
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine-components/AvatarLoader.js.map +1 -1
- package/lib/engine-components/Component.d.ts +3 -1
- package/lib/engine-components/Component.js +3 -4
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.d.ts +1 -1
- package/lib/engine-components/SceneSwitcher.js +1 -1
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/webxr/Avatar.js +3 -3
- package/lib/engine-components/webxr/Avatar.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/lib/engine-components-experimental/networking/PlayerSync.js +2 -1
- package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
- package/package.json +1 -1
- package/plugins/common/config.cjs +22 -6
- package/plugins/common/config.js +27 -11
- package/plugins/next/next.js +47 -4
- package/src/engine/codegen/register_types.ts +2 -2
- package/src/engine/engine_addressables.ts +19 -12
- package/src/engine/engine_context.ts +2 -0
- package/src/engine/engine_gameobject.ts +12 -3
- package/src/engine/engine_input.ts +12 -5
- package/src/engine/engine_license.ts +2 -1
- package/src/engine/engine_networking_instantiate.ts +1 -1
- package/src/engine/webcomponents/needle menu/needle-menu.ts +16 -10
- package/src/engine-components/AvatarLoader.ts +1 -1
- package/src/engine-components/Component.ts +9 -3
- package/src/engine-components/SceneSwitcher.ts +1 -1
- package/src/engine-components/webxr/Avatar.ts +3 -3
- package/src/engine-components/webxr/WebXRImageTracking.ts +5 -4
- package/src/engine-components-experimental/networking/PlayerSync.ts +1 -1
|
@@ -158,6 +158,8 @@ export class Context implements IContext {
|
|
|
158
158
|
// Note: this is due to a bug on OSX devices. See NE-5370
|
|
159
159
|
powerPreference: (DeviceUtilities.isiOS() || DeviceUtilities.isMacOS()) ? "default" : "high-performance",
|
|
160
160
|
stencil: true,
|
|
161
|
+
// logarithmicDepthBuffer: true,
|
|
162
|
+
// reverseDepthBuffer: true, // https://github.com/mrdoob/three.js/issues/29770
|
|
161
163
|
};
|
|
162
164
|
/** The default parameters that will be used when creating a new WebGLRenderer.
|
|
163
165
|
* Modify in global context to change the default parameters for all new contexts.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Bone, Object3D, Quaternion, SkinnedMesh, Vector3 } from "three";
|
|
2
2
|
|
|
3
|
+
import { type AssetReference } from "./engine_addressables.js";
|
|
3
4
|
import { __internalNotifyObjectDestroyed as __internalRemoveReferences, disposeObjectResources } from "./engine_assetdatabase.js";
|
|
4
5
|
import { ComponentLifecycleEvents } from "./engine_components_internal.js";
|
|
5
6
|
import { activeInHierarchyFieldName } from "./engine_constants.js";
|
|
@@ -10,7 +11,7 @@ import { InstantiateIdProvider } from "./engine_networking_instantiate.js";
|
|
|
10
11
|
import { assign } from "./engine_serialization_core.js";
|
|
11
12
|
import { Context, registerComponent } from "./engine_setup.js";
|
|
12
13
|
import { logHierarchy, setWorldPosition, setWorldQuaternion } from "./engine_three_utils.js";
|
|
13
|
-
import { type Constructor, type GuidsMap, type IComponent as Component, type IComponent, IEventList,type IGameObject as GameObject, type UIDProvider } from "./engine_types.js";
|
|
14
|
+
import { type Constructor, type GuidsMap, type IComponent as Component, type IComponent, IEventList, type IGameObject as GameObject, type UIDProvider } from "./engine_types.js";
|
|
14
15
|
import { getParam, tryFindObject } from "./engine_utils.js";
|
|
15
16
|
import { apply } from "./js-extensions/index.js";
|
|
16
17
|
|
|
@@ -307,9 +308,17 @@ declare type InstantiateReferenceMap = Record<string, ObjectCloneReference>;
|
|
|
307
308
|
*/
|
|
308
309
|
export declare type InstantiateContext = Readonly<InstantiateReferenceMap>;
|
|
309
310
|
|
|
310
|
-
export function instantiate(instance:
|
|
311
|
+
export function instantiate(instance: AssetReference, opts?: IInstantiateOptions | null): Promise<Object3D | null>
|
|
312
|
+
export function instantiate(instance: GameObject | Object3D, opts?: IInstantiateOptions | null): GameObject
|
|
313
|
+
export function instantiate(instance: AssetReference | GameObject | Object3D, opts?: IInstantiateOptions | null | undefined): GameObject | Promise<Object3D | null> {
|
|
314
|
+
|
|
315
|
+
if ("isAssetReference" in instance) {
|
|
316
|
+
return instance.instantiate(opts ?? undefined);
|
|
317
|
+
}
|
|
318
|
+
|
|
311
319
|
let options: InstantiateOptions | null = null;
|
|
312
|
-
|
|
320
|
+
|
|
321
|
+
if (opts !== null && opts !== undefined) {
|
|
313
322
|
// if x is defined assume this is a vec3 - this is just to not break everything at once and stay a little bit backwards compatible
|
|
314
323
|
if (opts["x"] !== undefined) {
|
|
315
324
|
options = new InstantiateOptions();
|
|
@@ -36,8 +36,15 @@ export const enum InputEvents {
|
|
|
36
36
|
KeyUp = "keyup",
|
|
37
37
|
KeyPressed = "keypress"
|
|
38
38
|
}
|
|
39
|
+
|
|
39
40
|
/** e.g. `pointerdown` */
|
|
40
|
-
|
|
41
|
+
type PointerEventNames = EnumToPrimitiveUnion<PointerEnumType>;
|
|
42
|
+
type KeyboardEventNames = EnumToPrimitiveUnion<KeyboardEnumType>;
|
|
43
|
+
export type InputEventNames = PointerEventNames | KeyboardEventNames;
|
|
44
|
+
|
|
45
|
+
declare type PointerEventListener = (evt: NEPointerEvent) => void;
|
|
46
|
+
declare type KeyboardEventListener = (evt: NEKeyboardEvent) => void;
|
|
47
|
+
declare type InputEventListener = PointerEventListener | KeyboardEventListener;
|
|
41
48
|
|
|
42
49
|
|
|
43
50
|
|
|
@@ -217,10 +224,6 @@ export class KeyEventArgs {
|
|
|
217
224
|
|
|
218
225
|
|
|
219
226
|
|
|
220
|
-
declare type PointerEventListener = (evt: NEPointerEvent) => void;
|
|
221
|
-
declare type KeyboardEventListener = (evt: NEKeyboardEvent) => void;
|
|
222
|
-
declare type InputEventListener = PointerEventListener | KeyboardEventListener;
|
|
223
|
-
|
|
224
227
|
export enum InputEventQueue {
|
|
225
228
|
Early = -100,
|
|
226
229
|
Default = 0,
|
|
@@ -254,6 +257,8 @@ export class Input implements IInput {
|
|
|
254
257
|
* @param callback The callback to call when the event is triggered
|
|
255
258
|
* @param options The options for adding the event listener
|
|
256
259
|
*/
|
|
260
|
+
addEventListener(type: PointerEventNames, callback: PointerEventListener, options?: EventListenerOptions);
|
|
261
|
+
addEventListener(type: KeyboardEventNames, callback: KeyboardEventListener, options?: EventListenerOptions);
|
|
257
262
|
addEventListener(type: InputEvents | InputEventNames, callback: InputEventListener, options?: EventListenerOptions): void {
|
|
258
263
|
if (!this._eventListeners[type]) this._eventListeners[type] = [];
|
|
259
264
|
|
|
@@ -284,6 +289,8 @@ export class Input implements IInput {
|
|
|
284
289
|
* @param callback The callback to remove
|
|
285
290
|
* @param options The options for removing the event listener
|
|
286
291
|
*/
|
|
292
|
+
removeEventListener(type: PointerEventNames, callback: PointerEventListener, options?: EventListenerOptions);
|
|
293
|
+
removeEventListener(type: KeyboardEventNames, callback: KeyboardEventListener, options?: EventListenerOptions);
|
|
287
294
|
removeEventListener(type: InputEvents | InputEventNames, callback: InputEventListener, options?: EventListenerOptions): void {
|
|
288
295
|
if (!this._eventListeners[type]) return;
|
|
289
296
|
if (!callback) return;
|
|
@@ -6,6 +6,8 @@ import { getParam } from "./engine_utils.js";
|
|
|
6
6
|
|
|
7
7
|
const debug = getParam("debuglicense");
|
|
8
8
|
|
|
9
|
+
const _licenseCheckResultChangedCallbacks: ((result: boolean) => void)[] = [];
|
|
10
|
+
|
|
9
11
|
// This is modified by a bundler (e.g. vite)
|
|
10
12
|
// Do not edit manually
|
|
11
13
|
let NEEDLE_ENGINE_LICENSE_TYPE: string = "basic";
|
|
@@ -36,7 +38,6 @@ export function hasCommercialLicense() {
|
|
|
36
38
|
return hasProLicense() || hasIndieLicense();
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
const _licenseCheckResultChangedCallbacks: ((result: boolean) => void)[] = [];
|
|
40
41
|
|
|
41
42
|
/** @internal */
|
|
42
43
|
export function onLicenseCheckResultChanged(cb: (result: boolean) => void) {
|
|
@@ -350,7 +350,7 @@ function instantiateSeeded(obj: GameObject, opts: IInstantiateOptions | null): {
|
|
|
350
350
|
return { seed: seed, instance: instance };
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
export declare type PrefabProviderCallback = (guid: string) => Promise<
|
|
353
|
+
export declare type PrefabProviderCallback = (guid: string) => Promise<Object3D | null>;
|
|
354
354
|
|
|
355
355
|
const registeredPrefabProviders: { [key: string]: PrefabProviderCallback } = {};
|
|
356
356
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Context } from "../../engine_context.js";
|
|
2
2
|
import { hasCommercialLicense, onLicenseCheckResultChanged } from "../../engine_license.js";
|
|
3
3
|
import { isLocalNetwork } from "../../engine_networking_utils.js";
|
|
4
|
-
import { DeviceUtilities,getParam } from "../../engine_utils.js";
|
|
4
|
+
import { DeviceUtilities, getParam } from "../../engine_utils.js";
|
|
5
5
|
import { onXRSessionStart, XRSessionEventArgs } from "../../xr/events.js";
|
|
6
6
|
import { ButtonsFactory } from "../buttons.js";
|
|
7
7
|
import { ensureFonts, iconFontUrl, loadFont } from "../fonts.js";
|
|
@@ -256,7 +256,12 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
256
256
|
if (!element && domElement.shadowRoot) {
|
|
257
257
|
element = domElement.shadowRoot.querySelector(elementName);
|
|
258
258
|
}
|
|
259
|
+
// if no needle-menu was found in the domelement then we search the document body
|
|
259
260
|
if (!element) {
|
|
261
|
+
element = window.document.body.querySelector(elementName) as NeedleMenuElement | null;
|
|
262
|
+
}
|
|
263
|
+
if (!element) {
|
|
264
|
+
// OK no menu element exists yet anywhere
|
|
260
265
|
element = NeedleMenuElement.create() as NeedleMenuElement;
|
|
261
266
|
if (domElement.shadowRoot)
|
|
262
267
|
domElement.shadowRoot.appendChild(element);
|
|
@@ -682,14 +687,15 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
682
687
|
});
|
|
683
688
|
|
|
684
689
|
try {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
690
|
+
// if the user has a license then we CAN hide the needle logo
|
|
691
|
+
// calling this method immediately will cause an issue with vite bundling tho
|
|
692
|
+
window.requestAnimationFrame(() => onLicenseCheckResultChanged(res => {
|
|
693
|
+
if (res == true && hasCommercialLicense() && !debugNonCommercial) {
|
|
694
|
+
let visible = this._userRequestedLogoVisible;
|
|
695
|
+
if (visible === undefined) visible = false;
|
|
696
|
+
this.#onSetLogoVisible(visible);
|
|
697
|
+
}
|
|
698
|
+
}));
|
|
693
699
|
} catch (e) {
|
|
694
700
|
console.error("[Needle Menu] License check failed.", e);
|
|
695
701
|
}
|
|
@@ -824,7 +830,7 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
824
830
|
this.logoContainer.style.display = "";
|
|
825
831
|
this.logoContainer.style.opacity = "1";
|
|
826
832
|
this.logoContainer.style.visibility = "visible";
|
|
827
|
-
if(visible) {
|
|
833
|
+
if (visible) {
|
|
828
834
|
this.root.classList.remove("logo-hidden");
|
|
829
835
|
this.root.classList.add("logo-visible");
|
|
830
836
|
}
|
|
@@ -52,7 +52,7 @@ export class AvatarLoader {
|
|
|
52
52
|
if (!root) {
|
|
53
53
|
const opts = new InstantiateOptions();
|
|
54
54
|
// opts.parent = context.scene.uuid;
|
|
55
|
-
root = GameObject.instantiate(utils.tryFindObject(avatarId, context.scene), opts);
|
|
55
|
+
root = GameObject.instantiate(utils.tryFindObject(avatarId, context.scene) as Object3D, opts);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
else root = avatarId;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Euler, Object3D, Quaternion, Scene, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
4
|
+
import { type AssetReference } from "../engine/engine_addressables.js";
|
|
4
5
|
import { addComponent, destroyComponentInstance, findObjectOfType, findObjectsOfType, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../engine/engine_components.js";
|
|
5
6
|
import { activeInHierarchyFieldName } from "../engine/engine_constants.js";
|
|
6
7
|
import { destroy, findByGuid, foreachComponent, HideFlags, type IInstantiateOptions, instantiate, isActiveInHierarchy, isActiveSelf, isDestroyed, isUsingInstancing, markAsInstancedRendered, setActive } from "../engine/engine_gameobject.js";
|
|
@@ -117,15 +118,20 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
|
|
|
117
118
|
*/
|
|
118
119
|
public static instantiateSynced(instance: GameObject | Object3D | null, opts: SyncInstantiateOptions): GameObject | null {
|
|
119
120
|
if (!instance) return null;
|
|
120
|
-
return syncInstantiate(instance
|
|
121
|
+
return syncInstantiate(instance, opts) as GameObject | null;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
/** Creates a new instance of the provided object (like cloning it including all components and children)
|
|
124
125
|
* @param instance object to instantiate
|
|
125
126
|
* @param opts options for the instantiation (e.g. with what parent, position, etc.)
|
|
126
127
|
*/
|
|
127
|
-
public static instantiate(instance:
|
|
128
|
-
|
|
128
|
+
public static instantiate(instance: AssetReference, opts?: IInstantiateOptions | null | undefined): Promise<Object3D | null>
|
|
129
|
+
public static instantiate(instance: GameObject | Object3D, opts?: IInstantiateOptions | null | undefined): GameObject
|
|
130
|
+
public static instantiate(instance: AssetReference | GameObject | Object3D, opts: IInstantiateOptions | null | undefined = null): GameObject | Promise<Object3D | null> {
|
|
131
|
+
if ('isAssetReference' in instance) {
|
|
132
|
+
return instantiate(instance as AssetReference, opts);
|
|
133
|
+
}
|
|
134
|
+
return instantiate(instance as GameObject | Object3D, opts) as GameObject;
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
/** Destroys a object on all connected clients (if you are in a networked session)
|
|
@@ -760,7 +760,7 @@ export class SceneSwitcher extends Behaviour {
|
|
|
760
760
|
}
|
|
761
761
|
this._lastLoadingScene = this.loadingScene;
|
|
762
762
|
if (!this._loadingScenePromise) {
|
|
763
|
-
this._loadingScenePromise = this.loadingScene?.loadAssetAsync();
|
|
763
|
+
this._loadingScenePromise = this.loadingScene?.loadAssetAsync().then(res => res != null);
|
|
764
764
|
}
|
|
765
765
|
await this._loadingScenePromise;
|
|
766
766
|
if (this._isCurrentlyLoading && this.loadingScene?.asset) {
|
|
@@ -101,7 +101,7 @@ export class Avatar extends Behaviour {
|
|
|
101
101
|
headObj.quaternion.x *= -1;
|
|
102
102
|
|
|
103
103
|
// HACK: XRFlag limitation workaround to make sure first person user head is never rendered
|
|
104
|
-
if (this.context.time.frameCount % 10 === 0) {
|
|
104
|
+
if (this.context.time.frameCount % 10 === 0 && this.head.asset) {
|
|
105
105
|
const xrflags = GameObject.getComponentsInChildren(this.head.asset, XRFlag);
|
|
106
106
|
for (const flag of xrflags) {
|
|
107
107
|
flag.enabled = false;
|
|
@@ -242,9 +242,9 @@ export class Avatar extends Behaviour {
|
|
|
242
242
|
await this.loadAvatarObjects(this.head, this.leftHand, this.rightHand);
|
|
243
243
|
|
|
244
244
|
this._leftHandMeshes = [];
|
|
245
|
-
this.leftHand.asset
|
|
245
|
+
this.leftHand.asset?.traverse((obj) => { if ((obj as Mesh)?.isMesh) this._leftHandMeshes!.push(obj as Mesh); });
|
|
246
246
|
this._rightHandMeshes = [];
|
|
247
|
-
this.rightHand.asset
|
|
247
|
+
this.rightHand.asset?.traverse((obj) => { if ((obj as Mesh)?.isMesh) this._rightHandMeshes!.push(obj as Mesh); });
|
|
248
248
|
|
|
249
249
|
if (PlayerState.isLocalPlayer(this.gameObject)) {
|
|
250
250
|
this._syncTransforms = GameObject.getComponentsInChildren(this.gameObject, SyncedTransform);
|
|
@@ -4,6 +4,7 @@ import { Object3DEventMap } from "three";
|
|
|
4
4
|
import { isDevEnvironment, showBalloonWarning } from "../../engine/debug/index.js";
|
|
5
5
|
import { AssetReference } from "../../engine/engine_addressables.js";
|
|
6
6
|
import { serializable } from "../../engine/engine_serialization.js";
|
|
7
|
+
import { IGameObject } from "../../engine/engine_types.js";
|
|
7
8
|
import { CircularBuffer, DeviceUtilities, getParam } from "../../engine/engine_utils.js";
|
|
8
9
|
import { type NeedleXREventArgs, NeedleXRSession } from "../../engine/xr/api.js";
|
|
9
10
|
import { IUSDExporterExtension } from "../../engine-components/export/usdz/Extension.js";
|
|
@@ -355,7 +356,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
355
356
|
}
|
|
356
357
|
}
|
|
357
358
|
|
|
358
|
-
private readonly imageToObjectMap = new Map<WebXRImageTrackingModel, { object:
|
|
359
|
+
private readonly imageToObjectMap = new Map<WebXRImageTrackingModel, { object: Object3D | null, frames: number, lastTrackingTime: number }>();
|
|
359
360
|
private readonly currentImages: WebXRTrackedImage[] = [];
|
|
360
361
|
|
|
361
362
|
|
|
@@ -456,7 +457,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
456
457
|
trackedData = { object: null, frames: 0, lastTrackingTime: Date.now() };
|
|
457
458
|
this.imageToObjectMap.set(model, trackedData);
|
|
458
459
|
|
|
459
|
-
model.object.loadAssetAsync().then((asset:
|
|
460
|
+
model.object.loadAssetAsync().then((asset: Object3D | null) => {
|
|
460
461
|
if (model.createObjectInstance && asset) {
|
|
461
462
|
asset = GameObject.instantiate(asset);
|
|
462
463
|
}
|
|
@@ -475,7 +476,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
475
476
|
if (xr.rig) {
|
|
476
477
|
xr.rig.gameObject.add(asset);
|
|
477
478
|
image.applyToObject(asset);
|
|
478
|
-
if (!asset.activeSelf)
|
|
479
|
+
if (!(asset as IGameObject).activeSelf)
|
|
479
480
|
GameObject.setActive(asset, true);
|
|
480
481
|
// InstancingUtil.markDirty(asset);
|
|
481
482
|
}
|
|
@@ -503,7 +504,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
503
504
|
xr.rig.gameObject.add(trackedData.object);
|
|
504
505
|
|
|
505
506
|
image.applyToObject(trackedData.object, this.smooth ? this.context.time.deltaTimeUnscaled * 3 : undefined);
|
|
506
|
-
if (!trackedData.object.activeSelf) {
|
|
507
|
+
if (!(trackedData.object as IGameObject).activeSelf) {
|
|
507
508
|
GameObject.setActive(trackedData.object, true);
|
|
508
509
|
}
|
|
509
510
|
// InstancingUtil.markDirty(trackedData.object);
|
|
@@ -36,7 +36,7 @@ export class PlayerSync extends Behaviour {
|
|
|
36
36
|
const assetReference = AssetReference.getOrCreateFromUrl(url);
|
|
37
37
|
if (!assetReference.asset) {
|
|
38
38
|
const i = await assetReference.loadAssetAsync();
|
|
39
|
-
GameObject.getOrAddComponent(i, PlayerState);
|
|
39
|
+
if(i) GameObject.getOrAddComponent(i, PlayerState);
|
|
40
40
|
}
|
|
41
41
|
const ps = new PlayerSync();
|
|
42
42
|
ps._internalInit(init);
|