zhouenguang 3 éve
szülő
commit
21b58bb8f8
6 módosított fájl, 843 hozzáadás és 834 törlés
  1. 18 14
      dist/index.html
  2. 48 47
      src/XAvatar.js
  3. 308 321
      src/XMaterialComponent.js
  4. 111 100
      src/XSceneManager.js
  5. 177 176
      src/XverseAvatar.js
  6. 181 176
      src/Xverse_Room.js

+ 18 - 14
dist/index.html

@@ -228,21 +228,25 @@
     var Me = Object.prototype.hasOwnProperty
     , Ie = Object.prototype.propertyIsEnumerable;
 
-    var Se = (i,e,t)=>e in i ? De(i, e, {
-        enumerable: !0,
-        configurable: !0,
-        writable: !0,
-        value: t
-    }) : i[e] = t
-    , oe = (i,e)=>{
-        for (var t in e || (e = {}))
-            Me.call(e, t) && Se(i, t, e[t]);
-        if (be)
-            for (var t of be(e))
-                Ie.call(e, t) && Se(i, t, e[t]);
-        return i
+    var Se = (obj, key, value) => 
+        key in obj ? Object.defineProperty(obj, key, {
+            enumerable: true,
+            configurable: true,
+            writable: true,
+            value: value
+        }) : obj[key] = value
+
+    , oe = (obj, propsObj)=>{
+        for (var t in propsObj || (propsObj = {}))
+            Me.call(propsObj, t) && Se(obj, t, propsObj[t]);
+        if (Object.getOwnPropertySymbols) {
+            for (var t of Object.getOwnPropertySymbols(propsObj))
+                Ie.call(propsObj, t) && Se(obj, t, propsObj[t]);
+        }
+        return obj
     }
-    , le = (i,e)=>Ne(i, we(e));
+    // 将propsObj的所有属性拷贝到obj
+    , le = (obj, propsObj) => Object.defineProperties(obj, Object.getOwnPropertyDescriptors(propsObj));
     
     var Oe = (i,e)=>{
         var t = {};

+ 48 - 47
src/XAvatar.js

@@ -32,53 +32,6 @@ export default class XAvatar {
         this._scene = void 0,
         this._transparent = 0,
 
-        this.hide = ()=>{
-            this.isHide = !0
-            this._hide()
-            return !this.isRender
-        },
-
-        this._show = ()=>{
-            this.isHide || (
-                this.setIsPickable(!0),
-                this.bbComponent._attachmentObservers.forEach((b,k)=>{
-                    k.setEnabled(!0)
-                }),
-                this.priority == 0 && (
-                    this.rootNode.setEnabled(!0),
-                    this.isRender = !0,
-                    this.avatarManager._updateBillboardStatus(this, BillboardStatus.SHOW),
-                    this.component.accessories.forEach(b=>{
-                        b.rootComponent.setEnabled(!0)
-                    }),
-                    this.controller == null || this.controller.playAnimation(this.controller.onPlay, this.controller.loop)
-                ),
-                this.component.accessories.forEach(b=>{
-                    b.rootComponent.setEnabled(!0)
-                })
-            )
-        },
-
-        this.show = ()=>{
-            this.isHide = !1
-            this._show()
-            return !!this.isRender
-        },
-
-        this.setAnimations = _=>{
-            this.controller.animations = _
-        },
-        
-        this.attachToAvatar = ( _, b=!1, k={x:0,y:0,z:0}, j=!1, $, _e ) => {
-            this.bbComponent.attachToAvatar(this, _, b, k, j, _e)
-        },
-
-        this.detachFromAvatar = ( _, b=!1 )=>{
-            this.bbComponent.detachFromAvatar(this, _, b)
-        },
-        this.getBbox = (_={})=>{
-            this.bbComponent.getBbox(this, _)
-        },
 
         this.id = id,
         this._avatarManager = avatarManager,
@@ -108,6 +61,54 @@ export default class XAvatar {
         })
     }
 
+    hide = ()=>{
+        this.isHide = !0
+        this._hide()
+        return !this.isRender
+    }
+
+    _show = ()=>{
+        this.isHide || (
+            this.setIsPickable(!0),
+            this.bbComponent._attachmentObservers.forEach((b,k)=>{
+                k.setEnabled(!0)
+            }),
+            this.priority == 0 && (
+                this.rootNode.setEnabled(!0),
+                this.isRender = !0,
+                this.avatarManager._updateBillboardStatus(this, BillboardStatus.SHOW),
+                this.component.accessories.forEach(b=>{
+                    b.rootComponent.setEnabled(!0)
+                }),
+                this.controller == null || this.controller.playAnimation(this.controller.onPlay, this.controller.loop)
+            ),
+            this.component.accessories.forEach(b=>{
+                b.rootComponent.setEnabled(!0)
+            })
+        )
+    }
+
+    show = ()=>{
+        this.isHide = !1
+        this._show()
+        return !!this.isRender
+    }
+
+    setAnimations = _=>{
+        this.controller.animations = _
+    }
+    
+    attachToAvatar = ( _, b=!1, k={x:0,y:0,z:0}, j=!1, $, _e ) => {
+        this.bbComponent.attachToAvatar(this, _, b, k, j, _e)
+    }
+
+    detachFromAvatar = ( _, b=!1 )=>{
+        this.bbComponent.detachFromAvatar(this, _, b)
+    }
+    getBbox = (_={})=>{
+        this.bbComponent.getBbox(this, _)
+    }
+
     tick() {
         this.cullingTick()
     }

+ 308 - 321
src/XMaterialComponent.js

@@ -3,301 +3,289 @@ import Logger from "./Logger.js";
 
 const logger = new Logger("XMaterial");
 export default class XMaterialComponent {
-  constructor(e, t) {
-    E(this, "scene");
-    E(this, "engine");
-    E(this, "yuvInfo");
-    E(this, "shaderMode");
-    E(this, "_panoInfo");
-    E(this, "_dynamic_size");
-    E(this, "_dynamic_babylonpose");
-    E(this, "_dynamic_textures");
-    E(this, "_dynamic_shaders");
-    E(this, "_scenemanager");
-    E(this, "_videoTexture");
-    E(this, "_videoElement");
-    E(this, "_lowModelShader");
-    E(this, "_defaultShader");
-    E(this, "_inputYUV420", !0);
-    E(this, "_inputPanoYUV420", !0);
-    E(this, "_videoRawYUVTexArray");
-    E(this, "_isUpdateYUV", !0);
-    E(
-      this,
-      "initMaterial",
-      async () =>
-        new Promise((resolve, t) => {
-          this._initDefaultShader();
-          if (this.shaderMode == 2) {
-            this.initDynamicData(
-              this._panoInfo.dynamicRange,
-              this._panoInfo.width,
-              this._panoInfo.height
-            ).then(() => {
-              this._initPureVideoShader();
-              this._prepareRender(this.yuvInfo);
-            });
-          } else if (this.shaderMode == 1) {
-            this._initPureVideoShader();
-            this._prepareRender(this.yuvInfo);
-          }
-          // else if(this.shaderMode == 0){
-          //     resolve(!0)
-          // }
-          resolve(!0);
-          // this.shaderMode == 2 ? this.initDynamicData(this._panoInfo.dynamicRange, this._panoInfo.width, this._panoInfo.height).then(()=>{
-          //     this._initPureVideoShader(),
-          //     this._prepareRender(this.yuvInfo)
-          // }
-          // ) : this.shaderMode == 1 ? (this._initPureVideoShader(),
-          // this._prepareRender(this.yuvInfo)) : this.shaderMode == 0,
-          // resolve(!0)
-        })
-    );
+  constructor(sceneManager, t) {
+    this.scene
+    this.engine
+    this.yuvInfo
+    this.shaderMode
+    this._panoInfo
+    this._dynamic_size
+    this._dynamic_babylonpose
+    this._dynamic_textures
+    this._dynamic_shaders
+    this._scenemanager
+    this._videoTexture
+    this._videoElement
+    this._lowModelShader
+    this._defaultShader
+    this._inputYUV420 = !0
+    this._inputPanoYUV420 = !0
+    this._videoRawYUVTexArray
+    this._isUpdateYUV = !0
 
-    E(this, "_initPureVideoContent", (focal_width_height) => {
-      if (this._inputYUV420) {
-        if (this._videoRawYUVTexArray.getVideoYUVTex(0) != null) {
-          this._lowModelShader.setTexture(
-            "texture_video",
-            this._videoRawYUVTexArray.getVideoYUVTex(0)
-          );
-          this._lowModelShader.setFloat("isYUV", 1);
-          BABYLON.Texture.WhenAllReady(
-            [this._videoRawYUVTexArray.getVideoYUVTex(0)],
-            () => {
-              this._changePureVideoLowModelShaderCanvasSize(focal_width_height);
-            }
-          );
-        }
+    this._scenemanager = sceneManager
+    this.scene = sceneManager.Scene
+    this.engine = this.scene.getEngine()
+    this.shaderMode = 1
+    this._dynamic_textures = []
+    this._dynamic_shaders = []
+    this._dynamic_babylonpose = []
+    this._videoRawYUVTexArray = new XVideoRawYUV(
+      this.scene,
+      t.videoResOriArray
+    )
+    this.shaderMode = t.shaderMode
+    t.yuvInfo && (this.yuvInfo = t.yuvInfo),
+    t.panoInfo && this.setPanoInfo(t.panoInfo);
+  }
+
+  initMaterial = async () => {
+    return new Promise((resolve, t) => {
+      this._initDefaultShader();
+      if (this.shaderMode == 2) {
+        this.initDynamicData(
+          this._panoInfo.dynamicRange,
+          this._panoInfo.width,
+          this._panoInfo.height
+        ).then(() => {
+          this._initPureVideoShader();
+          this._prepareRender(this.yuvInfo);
+        });
+      } else if (this.shaderMode == 1) {
+        this._initPureVideoShader();
+        this._prepareRender(this.yuvInfo);
       }
-      // else{
-      //     this._videoElement = e.videoElement;
-      //     this._videoTexture || (this._videoTexture = new VideoTexture("InterVideoTexture",this._videoElement,this.scene,!0,!1));
-      //     BABYLON.Texture.WhenAllReady([this._videoTexture], ()=>{
-      //         this._changePureVideoLowModelShaderCanvasSize({
-      //             width: this._videoElement.height,
-      //             height: this._videoElement.width,
-      //             fov: e.fov
-      //         })
-      //     });
-      //     this._lowModelShader.setTexture("texture_video", this._videoTexture);
-      //     this._lowModelShader.setFloat("isYUV", 0);
+      // else if(this.shaderMode == 0){
+      //     resolve(!0)
+      // }
+      resolve(!0);
+      // this.shaderMode == 2 ? this.initDynamicData(this._panoInfo.dynamicRange, this._panoInfo.width, this._panoInfo.height).then(()=>{
+      //     this._initPureVideoShader(),
+      //     this._prepareRender(this.yuvInfo)
       // }
-    });
-
-    E(this, "_changePureVideoLowModelShaderCanvasSize", (e) => {
-      var lowModelShader;
-      const fov = e.fov || 50;
-      const width = e.width || 720;
-      const height = e.height || 1280;
-      const focus = width / (2 * Math.tan((Math.PI * fov) / 360));
-      (lowModelShader = this._lowModelShader) == null ||
-        lowModelShader.setVector3(
-          "focal_width_height",
-          new BABYLON.Vector3(focus, width, height)
+      // ) : this.shaderMode == 1 ? (this._initPureVideoShader(),
+      // this._prepareRender(this.yuvInfo)) : this.shaderMode == 0,
+      // resolve(!0)
+    })
+  }
+
+  _initPureVideoContent = (focal_width_height) => {
+    if (this._inputYUV420) {
+      if (this._videoRawYUVTexArray.getVideoYUVTex(0) != null) {
+        this._lowModelShader.setTexture(
+          "texture_video",
+          this._videoRawYUVTexArray.getVideoYUVTex(0)
         );
-    });
-
-    E(this, "updateRawYUVData", (stream, width, height, fov=-1)=>{
-        fov == -1 && (fov = this.yuvInfo.fov);
-
-        if (this._isUpdateYUV == !0) {
-            console.log('执行:updateRawYUVData')
-            const yuvInfo = { width, height, fov }
-            const videosResOriArrayIndex = this._videoRawYUVTexArray.findId(width, height)
-            const currentVideoId = this._videoRawYUVTexArray.getCurrentVideoTexId();
-
-            if(currentVideoId < 0 || videosResOriArrayIndex != currentVideoId || fov != this.yuvInfo.fov)
-            {
-                this.yuvInfo.width = width;
-                this.yuvInfo.height = height;
-                this.yuvInfo.fov = fov;
-
-                this._videoRawYUVTexArray.setCurrentVideoTexId(videosResOriArrayIndex);
-                this._changeVideoRes(videosResOriArrayIndex);   // 设置texture_video
-                this._changePureVideoLowModelShaderCanvasSize(yuvInfo); // 设置focal_width_height
-                this._scenemanager.cameraComponent.cameraFovChange(yuvInfo);
-                this._scenemanager.yuvInfo = yuvInfo;
-            }
+        this._lowModelShader.setFloat("isYUV", 1);
+        BABYLON.Texture.WhenAllReady(
+          [this._videoRawYUVTexArray.getVideoYUVTex(0)],
+          () => {
+            this._changePureVideoLowModelShaderCanvasSize(focal_width_height);
+          }
+        );
+      }
+    }
+    // else{
+    //     this._videoElement = e.videoElement;
+    //     this._videoTexture || (this._videoTexture = new VideoTexture("InterVideoTexture",this._videoElement,this.scene,!0,!1));
+    //     BABYLON.Texture.WhenAllReady([this._videoTexture], ()=>{
+    //         this._changePureVideoLowModelShaderCanvasSize({
+    //             width: this._videoElement.height,
+    //             height: this._videoElement.width,
+    //             fov: e.fov
+    //         })
+    //     });
+    //     this._lowModelShader.setTexture("texture_video", this._videoTexture);
+    //     this._lowModelShader.setFloat("isYUV", 0);
+    // }
+  }
 
-            let VideoTexture = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)
-            if(VideoTexture != null){
-                // 更新视频流
-                VideoTexture.update(stream)
-                VideoTexture.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE)
-            }
+  _changePureVideoLowModelShaderCanvasSize = (e) => {
+    var lowModelShader;
+    const fov = e.fov || 50;
+    const width = e.width || 720;
+    const height = e.height || 1280;
+    const focus = width / (2 * Math.tan((Math.PI * fov) / 360));
+    (lowModelShader = this._lowModelShader) == null ||
+      lowModelShader.setVector3(
+        "focal_width_height",
+        new BABYLON.Vector3(focus, width, height)
+      );
+  }
 
-            //var o, a
-            //(o = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)) == null || o.update(stream),
-            //(a = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)) == null || a.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE)
-        }
-    });
+  updateRawYUVData = (stream, width, height, fov = -1) => {
+    fov == -1 && (fov = this.yuvInfo.fov);
 
-    E(this, "_changeVideoRes", (e) => {
-      this._lowModelShader.setTexture(
-        "texture_video",
-        this._videoRawYUVTexArray.getVideoYUVTex(e)
-      );
-    });
-
-    E(this, "initDynamicData", (dynamicRange, width, height) =>
-      new Promise((resolve, reject) => {
-        this.setDynamicSize(dynamicRange).then((a) => {
-          if (a) {
-            for (let s = 0; s < dynamicRange; ++s)
-              ((l) => {
-                this.initDynamicTexture(l, width, height),
-                  this.initDynamicShaders(l).then(() => {
-                    this._updatePanoShaderInput(l);
-                  });
-              })(s);
-            resolve(!0);
-          } else
-            reject(
-              new XMaterialError(
-                `[Engine] DynamicRoomSize (${dynamicRange}) is too small`
-              )
-            );
-        });
-      }).catch((n) => logger.error(`[Engine] ${n}`))
-    );
+    if (this._isUpdateYUV == !0) {
+      console.log('执行:updateRawYUVData')
+      const yuvInfo = { width, height, fov }
+      const videosResOriArrayIndex = this._videoRawYUVTexArray.findId(width, height)
+      const currentVideoId = this._videoRawYUVTexArray.getCurrentVideoTexId();
 
-    E(this, "_initDefaultShader", () => {
-      this._defaultShader == null &&
-        ((this._defaultShader = new BABYLON.GridMaterial(
-          "GridShader",
-          this.scene
-        )),
-        (this._defaultShader.gridRatio = 50),
-        (this._defaultShader.lineColor = new BABYLON.Color3(0, 0, 0.5)),
-        (this._defaultShader.majorUnitFrequency = 1),
-        (this._defaultShader.mainColor = new BABYLON.Color3(0.6, 0.6, 0.6)),
-        (this._defaultShader.backFaceCulling = !1));
-    });
-    E(this, "_initPureVideoShader", () => {
-      if (this._lowModelShader == null) {
-        const e = new BABYLON.ShaderMaterial(
-          "PureVideoShader",
-          this.scene,
-          {
-            vertexSource: pureVideoVertex,
-            fragmentSource: pureVideoFragment,
-          },
-          {
-            attributes: [
-              "uv",
-              "position",
-              "world0",
-              "world1",
-              "world2",
-              "world3",
-            ],
-            uniforms: ["view", "projection", "worldViewProjection", "world"],
-            defines: ["#define SHADOWFULLFLOAT"],
-          }
-        );
-        e.setTexture("shadowSampler", null),
-          e.setMatrix("lightSpaceMatrix", null),
-          e.setFloat("haveShadowLight", 0),
-          e.setTexture("texture_video", null),
-          e.setFloat("isYUV", this._inputYUV420 ? 1 : 0),
-          e.setFloat("fireworkLight", 0),
-          e.setVector3("fireworkLightPosition", new BABYLON.Vector3(0, 0, 0)),
-          e.setVector3(
-            "focal_width_height",
-            new BABYLON.Vector3(772.022491, 720, 1280)
-          ),
-          (e.backFaceCulling = !1),
-          (this._lowModelShader = e);
+      if (currentVideoId < 0 || videosResOriArrayIndex != currentVideoId || fov != this.yuvInfo.fov) {
+        this.yuvInfo.width = width;
+        this.yuvInfo.height = height;
+        this.yuvInfo.fov = fov;
+
+        this._videoRawYUVTexArray.setCurrentVideoTexId(videosResOriArrayIndex);
+        this._changeVideoRes(videosResOriArrayIndex);   // 设置texture_video
+        this._changePureVideoLowModelShaderCanvasSize(yuvInfo); // 设置focal_width_height
+        this._scenemanager.cameraComponent.cameraFovChange(yuvInfo);
+        this._scenemanager.yuvInfo = yuvInfo;
+      }
+
+      let VideoTexture = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)
+      if (VideoTexture != null) {
+        // 更新视频流
+        VideoTexture.update(stream)
+        VideoTexture.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE)
       }
-    });
-    E(
-      this,
-      "setDynamicSize",
-      (e) =>
-        new Promise((t, r) => {
-          e >= 1 && e <= 100
-            ? ((this._dynamic_size = e), t(!0))
-            : ((this._dynamic_size = 1), t(!1));
-        })
+
+      //var o, a
+      //(o = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)) == null || o.update(stream),
+      //(a = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)) == null || a.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE)
+    }
+  }
+
+  _changeVideoRes = (e) => {
+    this._lowModelShader.setTexture(
+      "texture_video",
+      this._videoRawYUVTexArray.getVideoYUVTex(e)
     );
-    E(this, "_isInDynamicRange", (e) => e < this._dynamic_size && e >= 0);
-    E(this, "initDynamicTexture", (e, t, r) => {
-      this._isInDynamicRange(e) &&
-        (this._dynamic_textures[e] != null &&
-          (this._dynamic_textures[e].dispose(),
-          (this._dynamic_textures[e] = null)),
-        (this._dynamic_textures[e] = new BABYLON.RawTexture(
-          null,
-          t,
-          r * 1.5,
-          BABYLON.Engine.TEXTUREFORMAT_LUMINANCE,
-          this.scene,
-          !1,
-          !0,
-          BABYLON.Texture.NEAREST_SAMPLINGMODE,
-          BABYLON.Engine.TEXTURETYPE_UNSIGNED_BYTE
-        )),
-        (this._dynamic_textures[e].name =
-          "Pano_Dynamic_" + e + "_" + Date.now()));
-    });
-    E(
-      this,
-      "initDynamicShaders",
-      (e) => (
-        logger.info("[Engine] Material init dynamic shader."),
-        new Promise((t, r) => {
-          this._dynamic_shaders[e] != null &&
-            this._dynamic_shaders[e].dispose();
-          const n = new BABYLON.ShaderMaterial(
-            "Pano_Shader_" + e,
-            this.scene,
-            {
-              vertexSource: panoVertex,
-              fragmentSource: panoFragment,
-            },
-            {
-              attributes: [
-                "uv",
-                "position",
-                "world0",
-                "world1",
-                "world2",
-                "world3",
-              ],
-              uniforms: ["view", "projection", "worldViewProjection", "world"],
-              defines: ["#define SHADOWFULLFLOAT"],
-            }
+  }
+
+  initDynamicData = (dynamicRange, width, height) => {
+    return new Promise((resolve, reject) => {
+      this.setDynamicSize(dynamicRange).then((a) => {
+        if (a) {
+          for (let s = 0; s < dynamicRange; ++s)
+            ((l) => {
+              this.initDynamicTexture(l, width, height),
+                this.initDynamicShaders(l).then(() => {
+                  this._updatePanoShaderInput(l);
+                });
+            })(s);
+          resolve(!0);
+        } else
+          reject(
+            new XMaterialError(
+              `[Engine] DynamicRoomSize (${dynamicRange}) is too small`
+            )
           );
-          n.setTexture("texture_pano", null),
-            n.setVector3("centre_pose", new BABYLON.Vector3(0, 0, 0)),
-            n.setFloat("isYUV", this._inputPanoYUV420 ? 1 : 0),
-            n.setTexture("shadowSampler", null),
-            n.setMatrix("lightSpaceMatrix", null),
-            n.setFloat("haveShadowLight", 0),
-            n.setFloat("fireworkLight", 0),
-            n.setVector3("fireworkLightPosition", new BABYLON.Vector3(0, 0, 0)),
-            (n.backFaceCulling = !1),
-            (this._dynamic_shaders[e] = n),
-            t(!0);
-        })
+      });
+    }).catch((n) => logger.error(`[Engine] ${n}`))
+  }
+
+  _initDefaultShader = () => {
+    if(this._defaultShader == null) {
+      this._defaultShader = new BABYLON.GridMaterial(
+        "GridShader",
+        this.scene
       )
-    );
-    (this._scenemanager = e),
-      (this.scene = e.Scene),
-      (this.engine = this.scene.getEngine()),
-      (this.shaderMode = 1),
-      (this._dynamic_textures = []),
-      (this._dynamic_shaders = []),
-      (this._dynamic_babylonpose = []),
-      (this._videoRawYUVTexArray = new XVideoRawYUV(
-        this.scene,
-        t.videoResOriArray
-      )),
-      (this.shaderMode = t.shaderMode),
-      t.yuvInfo != null && (this.yuvInfo = t.yuvInfo),
-      t.panoInfo != null && this.setPanoInfo(t.panoInfo);
+      this._defaultShader.gridRatio = 50
+      this._defaultShader.lineColor = new BABYLON.Color3(0, 0, 0.5)
+      this._defaultShader.majorUnitFrequency = 1
+      this._defaultShader.mainColor = new BABYLON.Color3(0.6, 0.6, 0.6)
+      this._defaultShader.backFaceCulling = !1
+    }
+  }
+
+  _initPureVideoShader = () => {
+    if (this._lowModelShader == null) {
+      const material = new BABYLON.ShaderMaterial(
+        "PureVideoShader",
+        this.scene, {
+          vertexSource: pureVideoVertex,
+          fragmentSource: pureVideoFragment,
+        }, {
+          attributes: ["uv", "position", "world0", "world1", "world2", "world3"],
+          uniforms: ["view", "projection", "worldViewProjection", "world"],
+          defines: ["#define SHADOWFULLFLOAT"],
+        }
+      );
+      material.setTexture("shadowSampler", null)
+      material.setMatrix("lightSpaceMatrix", null)
+      material.setFloat("haveShadowLight", 0)
+      material.setTexture("texture_video", null)
+      material.setFloat("isYUV", this._inputYUV420 ? 1 : 0)
+      material.setFloat("fireworkLight", 0)
+      material.setVector3("fireworkLightPosition", new BABYLON.Vector3(0, 0, 0))
+      material.setVector3(
+        "focal_width_height",
+        new BABYLON.Vector3(772.022491, 720, 1280)
+      )
+      material.backFaceCulling = !1
+      
+      this._lowModelShader = material
+    }
+  }
+
+  setDynamicSize = (e) => {
+    return new Promise((t, r) => {
+      e >= 1 && e <= 100
+        ? ((this._dynamic_size = e), t(!0))
+        : ((this._dynamic_size = 1), t(!1));
+    })
+  }
+
+  _isInDynamicRange = (e) => {
+    return e < this._dynamic_size && e >= 0
+  }
+
+  initDynamicTexture = (e, t, r) => {
+    this._isInDynamicRange(e) &&
+      (
+        this._dynamic_textures[e] != null && (
+          this._dynamic_textures[e].dispose(),
+          (this._dynamic_textures[e] = null)
+        ), (
+          this._dynamic_textures[e] = new BABYLON.RawTexture(
+            null,
+            t,
+            r * 1.5,
+            BABYLON.Engine.TEXTUREFORMAT_LUMINANCE,
+            this.scene,
+            !1,
+            !0,
+            BABYLON.Texture.NEAREST_SAMPLINGMODE,
+            BABYLON.Engine.TEXTURETYPE_UNSIGNED_BYTE
+          )
+        ), (
+          this._dynamic_textures[e].name =
+          "Pano_Dynamic_" + e + "_" + Date.now()
+        )
+      );
+  }
+
+  initDynamicShaders = (e) => {
+    logger.info("[Engine] Material init dynamic shader.")
+    return new Promise((resolve, r) => {
+      this._dynamic_shaders[e] != null && this._dynamic_shaders[e].dispose();
+
+      const material = new BABYLON.ShaderMaterial(
+        "Pano_Shader_" + e,
+        this.scene, {
+          vertexSource: panoVertex,
+          fragmentSource: panoFragment,
+        }, {
+          attributes: ["uv", "position", "world0", "world1", "world2", "world3"],
+          uniforms: ["view", "projection", "worldViewProjection", "world"],
+          defines: ["#define SHADOWFULLFLOAT"],
+        }
+      );
+      material.setTexture("texture_pano", null)
+      material.setVector3("centre_pose", new BABYLON.Vector3(0, 0, 0))
+      material.setFloat("isYUV", this._inputPanoYUV420 ? 1 : 0)
+      material.setTexture("shadowSampler", null)
+      material.setMatrix("lightSpaceMatrix", null)
+      material.setFloat("haveShadowLight", 0)
+      material.setFloat("fireworkLight", 0)
+      material.setVector3("fireworkLightPosition", new BABYLON.Vector3(0, 0, 0))
+      material.backFaceCulling = !1
+
+      this._dynamic_shaders[e] = material
+      resolve(!0);
+    })
   }
 
   stopYUVUpdate() {
@@ -365,7 +353,7 @@ export default class XMaterialComponent {
       (logger.info(
         `[Engine] changePanoImg, id=${e}, pose=${t.pose.position.x},${t.pose.position.y},${t.pose.position.z}`
       ),
-      !this._isInDynamicRange(e))
+        !this._isInDynamicRange(e))
     )
       return (
         logger.error(
@@ -380,9 +368,9 @@ export default class XMaterialComponent {
     const r = ue4Position2Xverse(t.pose.position);
     return (
       r &&
-        (this._dynamic_babylonpose[e] = {
-          position: r,
-        }),
+      (this._dynamic_babylonpose[e] = {
+        position: r,
+      }),
       new Promise((n, o) => {
         try {
           typeof t.data == "string"
@@ -393,11 +381,11 @@ export default class XMaterialComponent {
                 );
               }))
             : (this.isPanoYUV420() == !1 &&
-                this.initDynamicTexture(
-                  e,
-                  this._panoInfo.width,
-                  this._panoInfo.height
-                ),
+              this.initDynamicTexture(
+                e,
+                this._panoInfo.width,
+                this._panoInfo.height
+              ),
               this.setPanoYUV420(!0),
               this._dynamic_textures[e].update(t.data),
               this._dynamic_textures[e].updateSamplingMode(
@@ -410,9 +398,9 @@ export default class XMaterialComponent {
       }).then(
         (n) => (
           t.fov != null &&
-            this._scenemanager.cameraComponent.changeCameraFov(
-              (t.fov * Math.PI) / 180
-            ),
+          this._scenemanager.cameraComponent.changeCameraFov(
+            (t.fov * Math.PI) / 180
+          ),
           this._dynamic_shaders[e].setFloat(
             "isYUV",
             this._inputPanoYUV420 ? 1 : 0
@@ -557,32 +545,31 @@ export default class XMaterialComponent {
   }
 
   _updatePanoShaderInput(e) {
-      var n,s;
-      if (this._isInDynamicRange(e)) 
-      {
-          let shader = this._dynamic_shaders[e]
-          let avatarLight = this.scene.getLightByName("AvatarLight")
-
-          shader == null || (avatarLight ? (
-              shader.setFloat("haveShadowLight", 1),
-              shader.setTexture("shadowSampler", (n = avatarLight == null ? void 0 : avatarLight.getShadowGenerator()) == null ? void 0 : n.getShadowMapForRendering()),
-              shader.setMatrix("lightSpaceMatrix", (s = avatarLight == null ? void 0 : avatarLight.getShadowGenerator()) == null ? void 0 : s.getTransformMatrix())
-          ) : (
-              shader.setTexture("shadowSampler", null),
-              shader.setMatrix("lightSpaceMatrix", new Matrix),
-              shader.setFloat("haveShadowLight", 0)
-          ))
-
-          let fireworkLight = this.scene.getLightByName("fireworkLight")
-          if (fireworkLight) {
-              this.scene.registerBeforeRender(()=>{
-                  shader.setFloat("fireworkLight", fireworkLight.getScaledIntensity()),
-                  shader.setVector3("fireworkLightPosition", fireworkLight == null ? void 0 : fireworkLight.position)
-              });
-          } else {
-              const f = new BABYLON.PointLight("fireworkLight", new BABYLON.Vector3(0,0,0), this.scene);
-              f.intensity = 0
-          }
+    var n, s;
+    if (this._isInDynamicRange(e)) {
+      let shader = this._dynamic_shaders[e]
+      let avatarLight = this.scene.getLightByName("AvatarLight")
+
+      shader == null || (avatarLight ? (
+        shader.setFloat("haveShadowLight", 1),
+        shader.setTexture("shadowSampler", (n = avatarLight == null ? void 0 : avatarLight.getShadowGenerator()) == null ? void 0 : n.getShadowMapForRendering()),
+        shader.setMatrix("lightSpaceMatrix", (s = avatarLight == null ? void 0 : avatarLight.getShadowGenerator()) == null ? void 0 : s.getTransformMatrix())
+      ) : (
+        shader.setTexture("shadowSampler", null),
+        shader.setMatrix("lightSpaceMatrix", new Matrix),
+        shader.setFloat("haveShadowLight", 0)
+      ))
+
+      let fireworkLight = this.scene.getLightByName("fireworkLight")
+      if (fireworkLight) {
+        this.scene.registerBeforeRender(() => {
+          shader.setFloat("fireworkLight", fireworkLight.getScaledIntensity()),
+            shader.setVector3("fireworkLightPosition", fireworkLight == null ? void 0 : fireworkLight.position)
+        });
+      } else {
+        const f = new BABYLON.PointLight("fireworkLight", new BABYLON.Vector3(0, 0, 0), this.scene);
+        f.intensity = 0
       }
+    }
   }
 }

+ 111 - 100
src/XSceneManager.js

@@ -31,88 +31,45 @@ const getAlphaWidthMap = (i,e)=>{
 }
 
 export default class XSceneManager {
-    constructor(e, t) {
-        E(this, "scene");
-        E(this, "engine");
-        E(this, "canvas");
-        E(this, "gl");
-        E(this, "_yuvInfo");
-        E(this, "cameraParam");
-        E(this, "shaderMode");
-        E(this, "panoInfo");
-        E(this, "_initEngineScaleNumber");
-        E(this, "_forceKeepVertical", !1);
-        E(this, "_currentShader");
-        E(this, "_currentPanoId");
-        E(this, "_renderStatusCheckCount", 0);
-        E(this, "_renderStatusNotChecktCount", 0);
-        E(this, "_nonlinearCanvasResize", !1);
-        E(this, "_bChangeEngineSize", !0);
-        E(this, "_cameraManager");
-        E(this, "_lowpolyManager");
-        E(this, "_materialManager");
-        E(this, "_statisticManager");
-        E(this, "_breathPointManager");
-        E(this, "_skytv");
-        E(this, "_mv", []);
-        E(this, "_decalManager");
-        E(this, "_lightManager");
-        E(this, "_avatarManager");
-        E(this, "urlTransformer");
-        E(this, "_billboardManager");
-        E(this, "_backgroundImg");
-        E(this, "engineRunTimeStats");
-        E(this, "uploadHardwareSystemInfo", ()=>{
-            const e = this.statisticComponent.getHardwareRenderInfo()
-              , t = this.statisticComponent.getSystemInfo()
-              , r = {
-                driver: t.driver,
-                vender: t.vender,
-                webgl: t.version,
-                os: t.os
-            };
-            logger.warn(JSON.stringify(e)),
-            logger.warn(JSON.stringify(r))
-        }
-        );
-        E(this, "addNewLowPolyMesh", async(e,t)=>(this._currentShader == null && await this.initSceneManager(),
-        this._lowpolyManager.addNewLowPolyMesh(e, t, this._currentShader)));
-        E(this, "initSceneManager", async()=>(await this._materialManager.initMaterial(),this.applyShader()));
-        E(this, "registerAfterRender", ()=>{
-            var e;
-            if (this._forceKeepVertical) {
-                const t = this.canvas.width
-                  , r = this.canvas.height;
-                let n = 0
-                  , o = [[0, 0, 0, 0], [0, 0, 0, 0]];
-                if (((e = this._cameraManager.MainCamera) == null ? void 0 : e.fovMode) === BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED ? (n = Math.ceil((r - this._yuvInfo.height * t / this._yuvInfo.width) / 2),
-                o = [[0, 0, t, n], [0, r - n, t, n]]) : (n = Math.ceil((t - this._yuvInfo.width * r / this._yuvInfo.height) / 2),
-                o = [[0, 0, n, r], [t - n, 0, n, r]]),
-                n > 0) {
-                    this.gl.enable(this.gl.SCISSOR_TEST);
-                    for (let a = 0; a < o.length; ++a)
-                        this.gl.scissor(o[a][0], o[a][1], o[a][2], o[a][3]),
-                        this.gl.clearColor(0, 0, 0, 1),
-                        this.gl.clear(this.gl.COLOR_BUFFER_BIT);
-                    this.gl.disable(this.gl.SCISSOR_TEST)
-                }
-            }
-        }
-        );
-        E(this, "resetRender", ()=>{
-            this.scene.environmentTexture && (this.scene.environmentTexture._texture ? this.lightComponent.setIBL(this.scene.environmentTexture._texture.url) : this.scene.environmentTexture.url && this.lightComponent.setIBL(this.scene.environmentTexture.url))
-        }
-        );
-        const r = /iphone|ipad/gi.test(window.navigator.userAgent) || t.disableWebGL2
-          , n = new BABYLON.Engine(e,!0,{
+    constructor(canvas, t) {
+        this.scene
+        this.engine
+        this.canvas
+        this.gl
+        this._yuvInfo
+        this.cameraParam
+        this.shaderMode
+        this.panoInfo
+        this._initEngineScaleNumber
+        this._forceKeepVertical = !1
+        this._currentShader
+        this._currentPanoId
+        this._renderStatusCheckCount = 0
+        this._renderStatusNotChecktCount = 0
+        this._nonlinearCanvasResize = !1
+        this._bChangeEngineSize = !0
+        this._cameraManager
+        this._lowpolyManager
+        this._materialManager
+        this._statisticManager
+        this._breathPointManager
+        this._skytv
+        this._mv = []
+        this._decalManager
+        this._lightManager
+        this._avatarManager
+        this.urlTransformer
+        this._billboardManager
+        this._backgroundImg
+        this.engineRunTimeStats
+
+        this.engine = new BABYLON.Engine(canvas, !0, {
             preserveDrawingBuffer: !0,
             stencil: !0,
-            disableWebGL2Support: r
-        },!0)
-          , o = new BABYLON.Scene(n);
-        this.scene = o,
-        this.engine = n,
-        this.canvas = e,
+            disableWebGL2Support: /iphone|ipad/gi.test(window.navigator.userAgent) || t.disableWebGL2
+        }, !0),
+        this.scene = new BABYLON.Scene(this.engine),
+        this.canvas = canvas,
         this.scene.clearColor = new BABYLON.Color4(.7,.7,.7,1),
         this.engine.getCaps().parallelShaderCompile = void 0,
         this._initEngineScaleNumber = this.engine.getHardwareScalingLevel(),
@@ -121,27 +78,27 @@ export default class XSceneManager {
         this.scene.clearCachedVertexData(),
         this.scene.cleanCachedTextureBuffer(),
         // this.scene.debugLayer.show({ embedMode: true, }),    // BABYLON调试工具栏
+
         this.urlTransformer = t.urlTransformer || (s=>Promise.resolve(s)),
         t.logger && defaultLog.setLogger(t.logger),
-        this.gl = e.getContext("webgl2", {
-            preserveDrawingBuffer: !0
-        }) || e.getContext("webgl", {
-            preserveDrawingBuffer: !0
-        }) || e.getContext("experimental-webgl", {
-            preserveDrawingBuffer: !0
-        }),
+        
+        this.gl = canvas.getContext("webgl2", { preserveDrawingBuffer: !0 }) 
+        || canvas.getContext("webgl", { preserveDrawingBuffer: !0 }) 
+        || canvas.getContext("experimental-webgl", { preserveDrawingBuffer: !0 }),
         this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1),
+
         this._currentPanoId = 0,
-        t.forceKeepVertical != null && (this._forceKeepVertical = t.forceKeepVertical),
-        t.panoInfo != null && (this.panoInfo = t.panoInfo),
-        t.shaderMode != null && (this.shaderMode = t.shaderMode),
-        t.yuvInfo != null ? this._yuvInfo = t.yuvInfo : this._yuvInfo = {
+        t.forceKeepVertical && (this._forceKeepVertical = t.forceKeepVertical),
+        t.panoInfo && (this.panoInfo = t.panoInfo),
+        t.shaderMode && (this.shaderMode = t.shaderMode),
+        t.yuvInfo ? this._yuvInfo = t.yuvInfo : this._yuvInfo = {
             width: t.videoResOriArray[0].width,
             height: t.videoResOriArray[0].height,
             fov: 50
         },
-        t.cameraParam != null && (this.cameraParam = t.cameraParam),
-        t.nonlinearCanvasResize != null && (this._nonlinearCanvasResize = t.nonlinearCanvasResize),
+        t.cameraParam && (this.cameraParam = t.cameraParam),
+        t.nonlinearCanvasResize && (this._nonlinearCanvasResize = t.nonlinearCanvasResize),
+
         this._cameraManager = new XCameraComponent(this.canvas,this.scene,{
             cameraParam: this.cameraParam,
             yuvInfo: this._yuvInfo,
@@ -164,23 +121,77 @@ export default class XSceneManager {
         this.postprocessing(),
         this.initSceneManager(),
         this.engineRunTimeStats = new XEngineRunTimeStats,
-        /iphone/gi.test(window.navigator.userAgent) && window.devicePixelRatio && window.devicePixelRatio === 3 && window.screen.width === 375 && window.screen.height === 812 ? this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 2) : this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.8),
+
+        /iphone/gi.test(window.navigator.userAgent) 
+        && window.devicePixelRatio 
+        && window.devicePixelRatio === 3 
+        && window.screen.width === 375 
+        && window.screen.height === 812 
+        ? this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 2) 
+        : this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.8),
+        
         this.scene.registerBeforeRender(()=>{
             this._nonlinearCanvasResize && this._bChangeEngineSize && (this.setEngineSize(this._yuvInfo),
             this._bChangeEngineSize = !1)
-        }
-        ),
+        }),
         this.scene.registerAfterRender(()=>{
             this._nonlinearCanvasResize || this.registerAfterRender()
-        }
-        ),
+        }),
         window.addEventListener("resize", ()=>{
             this._nonlinearCanvasResize ? this._bChangeEngineSize = !0 : this.engine.resize()
-        }
-        ),
+        }),
         XBillboardManager.alphaWidthMap = getAlphaWidthMap("Arial", this.scene),
         this.uploadHardwareSystemInfo()
     }
+
+    uploadHardwareSystemInfo = ()=>{
+        const e = this.statisticComponent.getHardwareRenderInfo()
+            , t = this.statisticComponent.getSystemInfo()
+            , r = {
+            driver: t.driver,
+            vender: t.vender,
+            webgl: t.version,
+            os: t.os
+        };
+        logger.warn(JSON.stringify(e)),
+        logger.warn(JSON.stringify(r))
+    }
+
+    addNewLowPolyMesh = async(e,t)=>(
+        this._currentShader == null && await this.initSceneManager(),
+        this._lowpolyManager.addNewLowPolyMesh(e, t, this._currentShader)
+    )
+
+    initSceneManager = async()=>(await this._materialManager.initMaterial(),this.applyShader())
+
+    registerAfterRender = ()=>{
+        var e;
+        if (this._forceKeepVertical) {
+            const t = this.canvas.width
+                , r = this.canvas.height;
+            let n = 0
+                , o = [[0, 0, 0, 0], [0, 0, 0, 0]];
+            if (((e = this._cameraManager.MainCamera) == null ? void 0 : e.fovMode) === BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED ? (n = Math.ceil((r - this._yuvInfo.height * t / this._yuvInfo.width) / 2),
+            o = [[0, 0, t, n], [0, r - n, t, n]]) : (n = Math.ceil((t - this._yuvInfo.width * r / this._yuvInfo.height) / 2),
+            o = [[0, 0, n, r], [t - n, 0, n, r]]),
+            n > 0) {
+                this.gl.enable(this.gl.SCISSOR_TEST);
+                for (let a = 0; a < o.length; ++a)
+                    this.gl.scissor(o[a][0], o[a][1], o[a][2], o[a][3]),
+                    this.gl.clearColor(0, 0, 0, 1),
+                    this.gl.clear(this.gl.COLOR_BUFFER_BIT);
+                this.gl.disable(this.gl.SCISSOR_TEST)
+            }
+        }
+    }
+
+    resetRender = ()=>{
+        this.scene.environmentTexture && (
+            this.scene.environmentTexture._texture ? this.lightComponent.setIBL(this.scene.environmentTexture._texture.url) 
+            : this.scene.environmentTexture.url && this.lightComponent.setIBL(this.scene.environmentTexture.url)
+        )
+    }
+
     get yuvInfo() {
         return this.getCurrentShaderMode() == 1 ? this._yuvInfo : {
             width: -1,

+ 177 - 176
src/XverseAvatar.js

@@ -9,200 +9,201 @@ import CoreBroadcastType from "./enum/CoreBroadcastType.js"
 
 const logger = new Logger('xverse-avatar')
 export default class XverseAvatar extends EventEmitter {
-    constructor({userId: e, isHost: t, room: r, avatarId: n, isSelf: o, group: a=AvatarGroup.Npc}) {
+    constructor({userId, isHost, room, avatarId, isSelf, group=AvatarGroup.Npc}) {
         super();
-        E(this, "xAvatar");
-        E(this, "_isHost", !1);
-        E(this, "_room");
-        E(this, "_withModel", !1);
-        E(this, "_userId");
-        E(this, "group", AvatarGroup.User);
-        E(this, "state", "idle");
-        E(this, "isLoading", !0);
-        E(this, "_isMoving", !1);
-        E(this, "_isRotating", !1);
-        E(this, "_failed", !1);
-        E(this, "disconnected", !1);
-        E(this, "_avatarId");
-        E(this, "prioritySync", !1);
-        E(this, "priority", EAvatarRelationRank.Stranger);
-        E(this, "_avatarModel");
-        E(this, "_motionType", MotionType.Walk);
-        E(this, "isSelf", !1);
-        E(this, "_lastAnimTraceId", "");
-        E(this, "statusSyncQueue", new Queue);
-        E(this, "extraInfo", {});
-
-        E(this, "setPosition", pos => {
-            !this._room.signal.isUpdatedYUV || this.xAvatar == null || this.xAvatar.setPosition(positionPrecisionProtect(pos))
-        });
-
-        E(this, "setRotation", rota => {
-            !this._room.signal.isUpdatedYUV || this.xAvatar == null || this.xAvatar.setRotation(rotationPrecisionProtect(rota))
-        });
-
-        E(this, "stopAnimation", ()=>{
-            (this.xAvatar == null ? void 0 : this.xAvatar.controller) == null || this.xAvatar.controller.stopAnimation()
-        });
-
-        E(this, "_playAnimation", async(animationName, isLoop=!0, r=!1)=>{
-            if (!this._room.signal.isUpdatedYUV) return;
-
-            if (this.state !== "idle" && !r)
-                return logger.debug("_playAnimation", "state is not idle"),
-                Promise.resolve("_playAnimation, state is not idle");
-
-            const startTime = Date.now();
-            try {
-                if (!(this.xAvatar != null && this.xAvatar.controller))
-                    return Promise.reject(new InternalError(`[avatar: ${this.userId}] Play animation failed: ${animationName}, no controller`));
-                this.isSelf && setTimeout(()=>{
-                    logger.infoAndReportMeasurement({
-                        tag: animationName,
-                        startTime,
-                        value: 0,
-                        metric: "playAnimationStart"
-                    })
-                });
+        this.xAvatar
+        this._isHost = !1
+        this._room
+        this._withModel = !1
+        this._userId
+        this.group = AvatarGroup.User
+        this.state = "idle"
+        this.isLoading = !0
+        this._isMoving = !1
+        this._isRotating = !1
+        this._failed = !1
+        this.disconnected = !1
+        this._avatarId
+        this.prioritySync = !1
+        this.priority = EAvatarRelationRank.Stranger
+        this._avatarModel
+        this._motionType = MotionType.Walk
+        this.isSelf = !1
+        this._lastAnimTraceId = ""
+        this.statusSyncQueue = new Queue
+        this.extraInfo = {}
+
+        this.sayTimer
+
+        this._userId = userId,
+        this._room = room,
+        this.isSelf = isSelf || !1,
+        this._withModel = !!avatarId,
+        this._isHost = isHost || !1,
+        this._avatarId = avatarId,
+        this.group = group,
+        
+        this._room.modelManager.getAvatarModelList().then(avatarModelList=>{
+            const l = avatarModelList.find(u=>u.id === avatarId);
+            l && (this._avatarModel = l)
+        })
+    }
 
-                const uuid = util.uuid();
-                this._lastAnimTraceId = uuid,
-                await this.xAvatar.controller.playAnimation(animationName, isLoop),
-                uuid === this._lastAnimTraceId && !this.isMoving && !isLoop && animationName !== "Idle" && this.xAvatar.controller.playAnimation("Idle", isLoop).catch(s=>{
-                    logger.error(`[avatar: ${this.userId}] Play animation failed [force idle]`, s)
-                }
-                ),
-                this.isSelf && logger.infoAndReportMeasurement({
+    setPosition = pos => {
+        !this._room.signal.isUpdatedYUV || this.xAvatar == null || this.xAvatar.setPosition(positionPrecisionProtect(pos))
+    }
+
+    setRotation = rota => {
+        !this._room.signal.isUpdatedYUV || this.xAvatar == null || this.xAvatar.setRotation(rotationPrecisionProtect(rota))
+    }
+
+    stopAnimation = ()=>{
+        (this.xAvatar == null ? void 0 : this.xAvatar.controller) == null || this.xAvatar.controller.stopAnimation()
+    }
+
+    _playAnimation = async(animationName, isLoop=!0, r=!1)=>{
+        if (!this._room.signal.isUpdatedYUV) return;
+
+        if (this.state !== "idle" && !r)
+            return logger.debug("_playAnimation", "state is not idle"),
+            Promise.resolve("_playAnimation, state is not idle");
+
+        const startTime = Date.now();
+        try {
+            if (!(this.xAvatar != null && this.xAvatar.controller))
+                return Promise.reject(new InternalError(`[avatar: ${this.userId}] Play animation failed: ${animationName}, no controller`));
+            this.isSelf && setTimeout(()=>{
+                logger.infoAndReportMeasurement({
                     tag: animationName,
                     startTime,
-                    extra: {
-                        loop: isLoop
-                    },
-                    metric: "playAnimationEnd"
+                    value: 0,
+                    metric: "playAnimationStart"
                 })
-            } catch (err) {
-                return logger.error(`[avatar: ${this.userId}] Play animation failed: ${animationName}`, err),
-                this.isSelf && logger.infoAndReportMeasurement({
-                    tag: animationName,
-                    startTime,
-                    metric: "playAnimationEnd",
-                    error: err,
-                    extra: {
-                        loop: isLoop
-                    }
-                }),
-                Promise.reject(err)
+            });
+
+            const uuid = util.uuid();
+            this._lastAnimTraceId = uuid,
+            await this.xAvatar.controller.playAnimation(animationName, isLoop),
+            uuid === this._lastAnimTraceId && !this.isMoving && !isLoop && animationName !== "Idle" && this.xAvatar.controller.playAnimation("Idle", isLoop).catch(s=>{
+                logger.error(`[avatar: ${this.userId}] Play animation failed [force idle]`, s)
             }
-        });
+            ),
+            this.isSelf && logger.infoAndReportMeasurement({
+                tag: animationName,
+                startTime,
+                extra: {
+                    loop: isLoop
+                },
+                metric: "playAnimationEnd"
+            })
+        } catch (err) {
+            return logger.error(`[avatar: ${this.userId}] Play animation failed: ${animationName}`, err),
+            this.isSelf && logger.infoAndReportMeasurement({
+                tag: animationName,
+                startTime,
+                metric: "playAnimationEnd",
+                error: err,
+                extra: {
+                    loop: isLoop
+                }
+            }),
+            Promise.reject(err)
+        }
+    }
 
-        E(this, "changeComponents", async data => {
-            const {mode, endAnimation=""} = data || {}
-              , avatarComponents = JSON.parse(JSON.stringify(data.avatarComponents));
+    changeComponents = async data => {
+        const {mode, endAnimation=""} = data || {}
+          , avatarComponents = JSON.parse(JSON.stringify(data.avatarComponents));
 
-            let o = avatarComponentsValidate(avatarComponents, this._avatarModel);
-            !ChangeComponentsMode[mode] && !o && (o = new ParamError(`changeComponents failed, mode: ${mode} is invalid`))
+        let o = avatarComponentsValidate(avatarComponents, this._avatarModel);
+        !ChangeComponentsMode[mode] && !o && (o = new ParamError(`changeComponents failed, mode: ${mode} is invalid`))
 
-            return o ? (logger.error(o), Promise.reject(o)) 
-            : this._changeComponents({ avatarComponents, mode, endAnimation }).then(()=>{
-                this.isSelf && mode !== ChangeComponentsMode.Preview && this.avatarComponentsSync(this.avatarComponents)
-            })
-        });
+        return o ? (logger.error(o), Promise.reject(o)) 
+        : this._changeComponents({ avatarComponents, mode, endAnimation }).then(()=>{
+            this.isSelf && mode !== ChangeComponentsMode.Preview && this.avatarComponentsSync(this.avatarComponents)
+        })
+    }
+
+    _changeComponents = async data=>{
+        const {avatarComponents=[], mode} = data || {}
+          , startTime = Date.now();
 
-        E(this, "_changeComponents", async data=>{
-            const {avatarComponents=[], mode} = data || {}
-              , startTime = Date.now();
+        try {
+            if (!this.xAvatar) return Promise.reject(new InternalError("changeComponents failed, without instance: xAvatar"));
 
-            try {
-                if (!this.xAvatar) return Promise.reject(new InternalError("changeComponents failed, without instance: xAvatar"));
+            const a = await avatarComponentsModify(this._avatarModel, avatarComponents)
+              , s = []
+              , l = await avatarComponentsParser(this._avatarModel, a, this.avatarComponents);
 
-                const a = await avatarComponentsModify(this._avatarModel, avatarComponents)
-                  , s = []
-                  , l = await avatarComponentsParser(this._avatarModel, a, this.avatarComponents);
+            if (l.length === 0) return this.avatarComponents;
 
-                if (l.length === 0) return this.avatarComponents;
+            await this.beforeChangeComponentsHook(data);
+            for (const u of l) {
+                const {id, type, url, suitComb} = u;
+                s.push(this.xAvatar == null ? void 0 : this.xAvatar.addComponent(id, type, url, suitComb))
+            }
 
-                await this.beforeChangeComponentsHook(data);
-                for (const u of l) {
-                    const {id, type, url, suitComb} = u;
-                    s.push(this.xAvatar == null ? void 0 : this.xAvatar.addComponent(id, type, url, suitComb))
+            await Promise.all(s)
+            this.emit("componentsChanged", {
+                components: this.avatarComponents,
+                mode
+            })
+            this.isSelf && logger.infoAndReportMeasurement({
+                tag: "changeComponents",
+                startTime,
+                metric: "changeComponents",
+                extra: {
+                    inputComponents: avatarComponents,
+                    finalComponents: this.avatarComponents,
+                    mode: ChangeComponentsMode[mode]
                 }
+            })
+            return this.avatarComponents
+
+        } catch (error) {
+            this.isSelf && logger.infoAndReportMeasurement({
+                tag: "changeComponents",
+                startTime,
+                metric: "changeComponents",
+                error,
+                extra: {
+                    inputComponents: avatarComponents,
+                    finalComponents: this.avatarComponents,
+                    mode: ChangeComponentsMode[mode]
+                }
+            })
+            return Promise.reject(error)
+        }
+    }
 
-                await Promise.all(s)
-                this.emit("componentsChanged", {
-                    components: this.avatarComponents,
-                    mode
-                })
-                this.isSelf && logger.infoAndReportMeasurement({
-                    tag: "changeComponents",
-                    startTime,
-                    metric: "changeComponents",
-                    extra: {
-                        inputComponents: avatarComponents,
-                        finalComponents: this.avatarComponents,
-                        mode: ChangeComponentsMode[mode]
-                    }
-                })
-                return this.avatarComponents
+    avatarComponentsSync = e=>{
+        e = e.map(t=>({
+            type: t.type,
+            id: t.id
+        })),
+        this._room.actionsHandler.avatarComponentsSync(e)
+    }
 
-            } catch (error) {
-                this.isSelf && logger.infoAndReportMeasurement({
-                    tag: "changeComponents",
-                    startTime,
-                    metric: "changeComponents",
-                    error,
-                    extra: {
-                        inputComponents: avatarComponents,
-                        finalComponents: this.avatarComponents,
-                        mode: ChangeComponentsMode[mode]
-                    }
-                })
-                return Promise.reject(error)
-            }
-        });
-
-        E(this, "avatarComponentsSync", e=>{
-            e = e.map(t=>({
-                type: t.type,
-                id: t.id
-            })),
-            this._room.actionsHandler.avatarComponentsSync(e)
-        });
-
-        E(this, "hide", ()=>{
-            var e;
-            if ((e = this.xAvatar) != null && e.hide())
-                return Promise.resolve(`avatar: ${this.userId} hide success`);
-            {
-                const t = `avatar: ${this.userId} hide failed ${!this.xAvatar && "without instance: xAvatar"}`;
-                return logger.warn(t),
-                Promise.reject(t)
-            }
-        });
+    hide = ()=>{
+        var e;
+        if ((e = this.xAvatar) != null && e.hide())
+            return Promise.resolve(`avatar: ${this.userId} hide success`);
+        {
+            const t = `avatar: ${this.userId} hide failed ${!this.xAvatar && "without instance: xAvatar"}`;
+            return logger.warn(t),
+            Promise.reject(t)
+        }
+    }
 
-        E(this, "show", ()=>{
-            var e;
-            if ((e = this.xAvatar) != null && e.show())
-                return Promise.resolve(`avatar: ${this.userId} show success`);
-            {
-                const t = `avatar: ${this.userId} show failed ${!this.xAvatar && "without instance: xAvatar"}`;
-                return logger.warn(t),
-                Promise.reject(t)
-            }
-        });
-
-        E(this, "sayTimer");
-
-        this._userId = e,
-        this._room = r,
-        this.isSelf = o || !1,
-        this._withModel = !!n,
-        this._isHost = t || !1,
-        this._avatarId = n,
-        this.group = a,
-        this._room.modelManager.getAvatarModelList().then(s=>{
-            const l = s.find(u=>u.id === n);
-            l && (this._avatarModel = l)
-        })
+    show = ()=>{
+        var e;
+        if ((e = this.xAvatar) != null && e.show())
+            return Promise.resolve(`avatar: ${this.userId} show success`);
+        {
+            const t = `avatar: ${this.userId} show failed ${!this.xAvatar && "without instance: xAvatar"}`;
+            return logger.warn(t),
+            Promise.reject(t)
+        }
     }
 
     get avatarId() {

+ 181 - 176
src/Xverse_Room.js

@@ -30,109 +30,52 @@ const logger = new Logger("xverse-room");
 export default class Xverse_Room extends EventEmitter {
   constructor(e) {
     super();
-    E(this, "disableAutoTurn", !1);
-    E(this, "options");
-    E(this, "_currentNetworkOptions");
-    E(this, "lastSkinId");
-    E(this, "debug");
-    E(this, "isFirstDataUsed", !1);
-    E(this, "userId", null);
-    E(this, "pathManager", new PathManager());
-    E(this, "networkController");
-    E(this, "_startTime", Date.now());
-    E(this, "canvas");
-    E(this, "modelManager");
-    E(this, "eventsController");
-    E(this, "panorama");
-    E(this, "engineProxy");
-    E(this, "_id");
-    E(this, "skinList", []);
-    E(this, "isHost", !1);
-    E(this, "avatarManager", new XverseAvatarManager(this));
-    E(this, "effectManager", new XverseEffectManager(this));
-    E(this, "sceneManager");
-    E(this, "scene");
-    E(this, "breathPointManager");
-    E(this, "_currentState");
-    E(this, "joined", !1);
-    E(this, "disableRotate", !1);
-    E(this, "isPano", !1);
-    E(this, "movingByClick", !0);
-    E(this, "camera", new Camera(this));
-    E(this, "stats", new Stats(this));
-    E(this, "isUpdatedRawYUVData", !1);
-    E(this, "actionsHandler", new ActionsHandler(this));
-    E(this, "_currentClickingState", null);
-    E(this, "signal", new Signal(this));
-    E(this, "firstFrameTimestamp");
+    this.disableAutoTurn = !1;
+    this.options;
+    this._currentNetworkOptions;
+    this.lastSkinId;
+    this.debug;
+    this.isFirstDataUsed = !1;
+    this.userId = null;
+    this.pathManager = new PathManager();
+    this.networkController;
+    this._startTime = Date.now();
+    this.canvas;
+    this.modelManager;
+    this.eventsController;
+    this.panorama;
+    this.engineProxy;
+    this._id;
+    this.skinList = [];
+    this.isHost = !1;
+    this.avatarManager = new XverseAvatarManager(this);
+    this.effectManager = new XverseEffectManager(this);
+    this.sceneManager;
+    this.scene;
+    this.breathPointManager;
+    this._currentState;
+    this.joined = !1;
+    this.disableRotate = !1;
+    this.isPano = !1;
+    this.movingByClick = !0;
+    this.camera = new Camera(this);
+    this.stats = new Stats(this);
+    this.isUpdatedRawYUVData = !1;
+    this.actionsHandler = new ActionsHandler(this);
+    this._currentClickingState = null;
+    this.signal = new Signal(this);
+    this.firstFrameTimestamp;
+    this.moveToExtra = "";
 
-    E(this, "receiveRtcData", async () => {
-      logger.info("Invoke receiveRtcData");
-      let i = !1,
-        o = !1,
-        s = !1,
-        c = !1;
-        return this.viewMode === "serverless" ? (
-            logger.warn("set view mode to serverless"),
-            this.setViewMode("observer").then(()=>this, ()=>this)
-        ) : new Promise((resolve, reject) => {
-            const workers = this.networkController.rtcp.workers;
+    this.options = e
+    this.options.wsServerUrl || (this.options.wsServerUrl = SERVER_URLS.DEV)
+    this.modelManager = ModelManager.getInstance(e.appId, e.releaseId)
+    this.updateReporter()
 
-            workers.registerFunction("signal", data => {
-                // 更新坐标数据
-                data.signal.newUserStates && data.signal.newUserStates[0] && (data.signal.newUserStates[0].userId = this.userId)  // todo 写死数据纠正
-                this.signal.handleSignal(data, reject)
-            }), 
-
-            workers.registerFunction("stream", data => {
-                // 更新视频贴图数据
-                this.emit("streamTimestamp", {
-                    timestamp: Date.now()
-                })
-                o || (o = !0, logger.info("Invoke stream event"))
-                if (data.stream) {
-                    s || (s = !0, logger.info("Invoke updateRawYUVData"))
-                    this.isUpdatedRawYUVData = !1;
-                    const $ = this._currentState.skin == null ? void 0 : this._currentState.skin.fov;
-                    this.sceneManager.materialComponent.updateRawYUVData(data.stream, data.width, data.height, $)
-                    this.isUpdatedRawYUVData = !0
-                }
-                if(!i){
-                    logger.info("Invoke isAfterRenderRegistered")
-                    i = !0
-                    this.scene.registerAfterRender(() => {
-                        this.engineProxy.frameRenderNumber >= 2 
-                        && (c || (
-                            c = !0, 
-                            logger.info("Invoke registerAfterRender")), 
-                            this.isFirstDataUsed || (logger.info("Invoke isStreamAvailable"), 
-                            this.isFirstDataUsed = !0, 
-                            this.firstFrameTimestamp = Date.now(), 
-                            resolve(this), 
-                            this.afterJoinRoom()
-                        ))
-                    })
-                }
-            }), 
-            this.panorama.bindListener(() => {
-                resolve(this)
-                this.afterJoinRoom()
-            }), 
-            workers.registerFunction("reconnectedFrame", () => {}), 
-            logger.info("Invoke decoderWorker.postMessage"), 
-            workers.decoderWorker.postMessage({
-                t: 5
-            })
-        })
-    });
-    E(this, "moveToExtra", "");
-    (this.options = e),
-      this.options.wsServerUrl || (this.options.wsServerUrl = SERVER_URLS.DEV),
-      (this.modelManager = ModelManager.getInstance(e.appId, e.releaseId)),
-      this.updateReporter();
     const n = e,
       { canvas: t } = n,
       r = Oe(n, ["canvas"]);
+
     logger.infoAndReportMeasurement({
       metric: "startJoinRoomAt",
       startTime: Date.now(),
@@ -142,6 +85,67 @@ export default class Xverse_Room extends EventEmitter {
     });
   }
 
+  receiveRtcData = async () => {
+    logger.info("Invoke receiveRtcData");
+    let i = !1,
+      o = !1,
+      s = !1,
+      c = !1;
+    return this.viewMode === "serverless" ? (
+      logger.warn("set view mode to serverless"),
+      this.setViewMode("observer").then(() => this, () => this)
+    ) : new Promise((resolve, reject) => {
+      const workers = this.networkController.rtcp.workers;
+
+      workers.registerFunction("signal", data => {
+        // 更新坐标数据
+        data.signal.newUserStates && data.signal.newUserStates[0] && (data.signal.newUserStates[0].userId = this.userId)  // todo 写死数据纠正
+        this.signal.handleSignal(data, reject)
+      }),
+
+      workers.registerFunction("stream", data => {
+        // 更新视频贴图数据
+        this.emit("streamTimestamp", {
+          timestamp: Date.now()
+        })
+        o || (o = !0, logger.info("Invoke stream event"))
+        if (data.stream) {
+          s || (s = !0, logger.info("Invoke updateRawYUVData"))
+          this.isUpdatedRawYUVData = !1;
+          const $ = this._currentState.skin == null ? void 0 : this._currentState.skin.fov;
+          this.sceneManager.materialComponent.updateRawYUVData(data.stream, data.width, data.height, $)
+          this.isUpdatedRawYUVData = !0
+        }
+        if (!i) {
+          logger.info("Invoke isAfterRenderRegistered")
+          i = !0
+          this.scene.registerAfterRender(() => {
+            this.engineProxy.frameRenderNumber >= 2
+              && (c || (
+                c = !0,
+                logger.info("Invoke registerAfterRender")),
+                this.isFirstDataUsed || (logger.info("Invoke isStreamAvailable"),
+                  this.isFirstDataUsed = !0,
+                  this.firstFrameTimestamp = Date.now(),
+                  resolve(this),
+                  this.afterJoinRoom()
+                ))
+          })
+        }
+      }),
+
+      this.panorama.bindListener(() => {
+        resolve(this)
+        this.afterJoinRoom()
+      }),
+      workers.registerFunction("reconnectedFrame", () => { }),
+      logger.info("Invoke decoderWorker.postMessage"),
+      workers.decoderWorker.postMessage({
+        t: 5
+      })
+    })
+  }
+
   get currentNetworkOptions() {
     return this._currentNetworkOptions;
   }
@@ -185,24 +189,24 @@ export default class Xverse_Room extends EventEmitter {
   get currentClickingState() {
     return this._currentClickingState;
   }
-  afterJoinRoomHook() {}
-  beforeJoinRoomResolveHook() {}
-  afterReconnectedHook() {}
-  handleSignalHook(e) {}
-  skinChangedHook() {}
-  async beforeStartGameHook(e) {}
-  loadAssetsHook() {}
-  afterUserAvatarLoadedHook() {}
-  audienceViewModeHook() {}
-  setViewModeToObserver() {}
-  handleVehicleHook(e) {}
-  
+  afterJoinRoomHook() { }
+  beforeJoinRoomResolveHook() { }
+  afterReconnectedHook() { }
+  handleSignalHook(e) { }
+  skinChangedHook() { }
+  async beforeStartGameHook(e) { }
+  loadAssetsHook() { }
+  afterUserAvatarLoadedHook() { }
+  audienceViewModeHook() { }
+  setViewModeToObserver() { }
+  handleVehicleHook(e) { }
+
   updateReporter() {
-      const {avatarId, skinId, userId, roomId, role, appId, wsServerUrl} = this.options;
-      reporter.updateHeader({ userId }),
+    const { avatarId, skinId, userId, roomId, role, appId, wsServerUrl } = this.options;
+    reporter.updateHeader({ userId }),
       reporter.updateBody({ roomId, role, skinId, avatarId, appId, wsServerUrl })
   }
-  
+
   async initRoom() {
     const { timeout: e = DEFAULT_JOINROOM_TIMEOUT } = this.options;
     if (util.isSupported()) {
@@ -213,42 +217,42 @@ export default class Xverse_Room extends EventEmitter {
   }
 
   async _initRoom() {
-      const e = this.validateOptions(this.options);
-      if(e) {
-          return logger.error("initRoom param error", e),
-          Promise.reject(e);
-      }
-      const {
-          canvas, avatarId, skinId, userId, wsServerUrl, role, token, pageSession, rotationRenderType, isAllSync=!1, appId, camera, player, 
-          avatarComponents, nickname, avatarScale, firends=[], syncByEvent=!1, areaName, attitude=MotionType.Walk, pathName, viewMode="full", 
-          person, roomId, roomTypeId, hasAvatar=!1, syncToOthers=!1, prioritySync=!1, extra, removeWhenDisconnected=!0
-      } = this.options;
-      this.setCurrentNetworkOptions({
-          avatarId, skinId, roomId, userId, wsServerUrl, role, token, pageSession, rotationRenderType, isAllSync, appId, camera, player,
-          avatarComponents, nickname, avatarScale, firends, syncByEvent, areaName, attitude, pathName,
-          person, roomTypeId, hasAvatar, syncToOthers, prioritySync, extra, removeWhenDisconnected
-      });
-        
-      this.userId = userId;
-      this.canvas = canvas;
-      areaName && (this.pathManager.currentArea = areaName);
-      this.networkController = new NetworkController(this);
-      this.setCurrentState({ areaName, pathName, attitude, speed: 0, viewMode, state: this.networkController._state, skinId });
-      try {
-          await Promise.all([this.initNetwork(), this.initConfig(), this.initWasm()]),
-          logger.info("network config wasm all ready, start to create game");
-          const skin = await this.requestCreateRoom({skinId})
-            , skinRoute = skin.routeList.find(route => route.areaName === areaName)
-            , speed = ((skinRoute == null ? void 0 : skinRoute.step) || 7.5) * 30;
-          this.updateCurrentState({ skin, skinId: skin.id, versionId: skin.versionId, speed }),
-          await this.initEngine(skin)
-      } catch (e) {
-          return Promise.reject(e)
-      }
-      this.beforeJoinRoomResolve();
-      return this.receiveRtcData()
-  }
-  
+    const e = this.validateOptions(this.options);
+    if (e) {
+      return logger.error("initRoom param error", e),
+        Promise.reject(e);
+    }
+    const {
+      canvas, avatarId, skinId, userId, wsServerUrl, role, token, pageSession, rotationRenderType, isAllSync = !1, appId, camera, player,
+      avatarComponents, nickname, avatarScale, firends = [], syncByEvent = !1, areaName, attitude = MotionType.Walk, pathName, viewMode = "full",
+      person, roomId, roomTypeId, hasAvatar = !1, syncToOthers = !1, prioritySync = !1, extra, removeWhenDisconnected = !0
+    } = this.options;
+    this.setCurrentNetworkOptions({
+      avatarId, skinId, roomId, userId, wsServerUrl, role, token, pageSession, rotationRenderType, isAllSync, appId, camera, player,
+      avatarComponents, nickname, avatarScale, firends, syncByEvent, areaName, attitude, pathName,
+      person, roomTypeId, hasAvatar, syncToOthers, prioritySync, extra, removeWhenDisconnected
+    });
+
+    this.userId = userId;
+    this.canvas = canvas;
+    areaName && (this.pathManager.currentArea = areaName);
+    this.networkController = new NetworkController(this);
+    this.setCurrentState({ areaName, pathName, attitude, speed: 0, viewMode, state: this.networkController._state, skinId });
+    try {
+      await Promise.all([this.initNetwork(), this.initConfig(), this.initWasm()]),
+        logger.info("network config wasm all ready, start to create game");
+      const skin = await this.requestCreateRoom({ skinId })
+        , skinRoute = skin.routeList.find(route => route.areaName === areaName)
+        , speed = ((skinRoute == null ? void 0 : skinRoute.step) || 7.5) * 30;
+      this.updateCurrentState({ skin, skinId: skin.id, versionId: skin.versionId, speed }),
+        await this.initEngine(skin)
+    } catch (e) {
+      return Promise.reject(e)
+    }
+    this.beforeJoinRoomResolve();
+    return this.receiveRtcData()
+  }
+
   beforeJoinRoomResolve() {
     this.setupStats(),
       (this.eventsController = new EventsController(this)),
@@ -281,28 +285,28 @@ export default class Xverse_Room extends EventEmitter {
         .then((i) => {
           this.avatarManager.handleAvatar(i);
         })
-        .catch(() => {});
+        .catch(() => { });
     }, 2e3);
   }
   afterReconnected() {
     this.avatarManager.clearOtherUsers(), this.afterReconnectedHook();
   }
   leave() {
-      return logger.info("Invoke room.leave"),
+    return logger.info("Invoke room.leave"),
       this.eventsController == null || this.eventsController.clearEvents(),
       this.networkController == null || this.networkController.quit(),
       this
   }
-  
+
   validateOptions(e) {
-      const {canvas, avatarId, skinId, userId, role, roomId, token, appId, avatarComponents} = e || {}
-      const h = [];
-      canvas instanceof HTMLCanvasElement || h.push(new ParamError("`canvas` must be instanceof of HTMLCanvasElement"));
-      (!userId || typeof userId != "string") && h.push(new ParamError("`userId` must be string"));
-      (!token || typeof token != "string") && h.push(new ParamError("`token` must be string"));
-      (!appId || typeof appId != "string") && h.push(new ParamError("`appId` must be string"));
-      role == "audience" || (!avatarId || !skinId) && h.push(new ParamError("`avatarId` and `skinId` is required when create room"));
-      return h[0]
+    const { canvas, avatarId, skinId, userId, role, roomId, token, appId, avatarComponents } = e || {}
+    const h = [];
+    canvas instanceof HTMLCanvasElement || h.push(new ParamError("`canvas` must be instanceof of HTMLCanvasElement"));
+    (!userId || typeof userId != "string") && h.push(new ParamError("`userId` must be string"));
+    (!token || typeof token != "string") && h.push(new ParamError("`token` must be string"));
+    (!appId || typeof appId != "string") && h.push(new ParamError("`appId` must be string"));
+    role == "audience" || (!avatarId || !skinId) && h.push(new ParamError("`avatarId` and `skinId` is required when create room"));
+    return h[0]
   }
 
   async initNetwork() {
@@ -330,7 +334,7 @@ export default class Xverse_Room extends EventEmitter {
           group: "joinRoom",
           error: t,
         }),
-        t)
+          t)
       );
     }
   }
@@ -358,7 +362,7 @@ export default class Xverse_Room extends EventEmitter {
           group: "joinRoom",
           error: t,
         }),
-        t)
+          t)
       );
     }
   }
@@ -379,6 +383,7 @@ export default class Xverse_Room extends EventEmitter {
         });
       return;
     } catch (r) {
+      console.error(r)
       let n = r;
       return (
         r.code !== Codes.InitEngineTimeout && (n = new InitEngineError()),
@@ -435,7 +440,7 @@ export default class Xverse_Room extends EventEmitter {
           startTime: i,
           error: o,
         }),
-        o)
+          o)
       );
     }
   }
@@ -459,9 +464,9 @@ export default class Xverse_Room extends EventEmitter {
           camera: n,
         }),
         this.options.player ||
-          this.updateCurrentNetworkOptions({
-            player: player,
-          });
+        this.updateCurrentNetworkOptions({
+          player: player,
+        });
     }
     if (this.viewMode === "serverless") return skin;
     try {
@@ -499,7 +504,7 @@ export default class Xverse_Room extends EventEmitter {
   reconnect() {
     this.networkController.reconnect();
   }
-  async setViewMode(e) {}
+  async setViewMode(e) { }
   handleRepetLogin() {
     logger.warn("receive " + Codes.RepeatLogin + " for repeat login"),
       this.emit("repeatLogin"),
@@ -552,19 +557,19 @@ export default class Xverse_Room extends EventEmitter {
   updateCurrentState(e) {
     e.skinId &&
       ((this.lastSkinId = this.currentState.skinId),
-      this.updateCurrentNetworkOptions({
-        skinId: e.skinId,
-      })),
-      e.versionId &&
         this.updateCurrentNetworkOptions({
-          versionId: e.versionId,
-        }),
+          skinId: e.skinId,
+        })),
+      e.versionId &&
+      this.updateCurrentNetworkOptions({
+        versionId: e.versionId,
+      }),
       Object.assign(this._currentState, e);
   }
 
-  afterSetUrlHook() {}
-  afterTvStopedHook() {}
-  afterTvPlayedHook() {}
+  afterSetUrlHook() { }
+  afterTvStopedHook() { }
+  afterTvPlayedHook() { }
   pageShowHandler() {
     this.engineProxy.setEnv(this.skin), (this.allowRender = !0);
   }