Ver código fonte

更新新版

xushiting 3 anos atrás
pai
commit
2d69830aed
100 arquivos alterados com 13696 adições e 185406 exclusões
  1. 1 218
      dist/assets/config.json
  2. 783 668
      dist/index.html
  3. 0 1371
      dist/libs/decoder copy.js
  4. 39 6
      dist/libs/decoder.js
  5. 1 1
      dist/libs/nipplejs.min.js
  6. 0 15
      dist/libs/toastify-js
  7. 12 12
      dist/shader.js
  8. 0 168842
      index.js
  9. 554 447
      src/ActionsHandler.js
  10. 128 144
      src/BaseTable.js
  11. 199 64
      src/BreathPoint.js
  12. 11 25
      src/Broadcast.js
  13. 185 156
      src/Camera.js
  14. 39 85
      src/CircularArray.js
  15. 25 24
      src/DataStorage.js
  16. 42 42
      src/Debug.js
  17. 465 491
      src/EngineProxy.js
  18. 7 0
      src/Error/CodeErrorMap.js
  19. 12 59
      src/Error/XverseError.js
  20. 35 36
      src/EventsController.js
  21. 92 90
      src/EventsManager.js
  22. 9 14
      src/Heartbeat.js
  23. 85 141
      src/Http.js
  24. 0 95
      src/Http1.js
  25. 0 147
      src/Http2.js
  26. 165 45
      src/JoyStick.js
  27. 23 75
      src/Logger.js
  28. 230 145
      src/ModelManager.js
  29. 157 194
      src/NetworkController.js
  30. 5 4
      src/NetworkMonitor.js
  31. 75 52
      src/Panorama.js
  32. 8 8
      src/PathManager.js
  33. 43 45
      src/Pool.js
  34. 5 9
      src/PoolObject.js
  35. 128 119
      src/Preload.js
  36. 13 12
      src/Queue.js
  37. 59 48
      src/Reporter.js
  38. 76 74
      src/RotationEvent.js
  39. 142 122
      src/Rtcp.js
  40. 16 17
      src/RunTimeArray.js
  41. 19 16
      src/SecondArray.js
  42. 120 145
      src/Signal.js
  43. 247 286
      src/Socket.js
  44. 45 64
      src/StaticMeshEvent.js
  45. 535 338
      src/Stats.js
  46. 31 38
      src/Stream.js
  47. 112 44
      src/TV.js
  48. 8 9
      src/Timeout.js
  49. 0 1575
      src/Workers-bk.js
  50. 1234 1389
      src/Workers.js
  51. 240 225
      src/XAnimationController.js
  52. 314 351
      src/XAvatar.js
  53. 257 258
      src/XAvatarBillboardComponent.js
  54. 141 157
      src/XAvatarComopnent.js
  55. 278 272
      src/XAvatarLoader.js
  56. 707 558
      src/XAvatarManager.js
  57. 149 139
      src/XBillboard.js
  58. 131 98
      src/XBillboardManager.js
  59. 212 274
      src/XBreathPointManager.js
  60. 253 196
      src/XCameraComponent.js
  61. 61 64
      src/XDecal.js
  62. 179 179
      src/XDecalManager.js
  63. 46 50
      src/XDecalMaterial.js
  64. 6 3
      src/XEngineRunTimeStats.js
  65. 99 78
      src/XLightManager.js
  66. 286 547
      src/XMaterialComponent.js
  67. 74 76
      src/XParticleManager.js
  68. 10 10
      src/XRain.js
  69. 269 261
      src/XSceneManager.js
  70. 16 20
      src/XSpriteManager.js
  71. 114 106
      src/XStaticMesh.js
  72. 414 433
      src/XStaticMeshComponent.js
  73. 73 80
      src/XStaticMeshFromOneGltf.js
  74. 34 42
      src/XStats.js
  75. 451 450
      src/XSubSequence.js
  76. 211 245
      src/XTelevision.js
  77. 36 26
      src/XVideoRawYUV.js
  78. 123 56
      src/Xverse.js
  79. 414 378
      src/XverseAvatar.js
  80. 458 315
      src/XverseAvatarManager.js
  81. 53 29
      src/XverseEffectManager.js
  82. 518 8
      src/XverseRoom.js
  83. 0 572
      src/Xverse_Room.js
  84. 0 29
      src/defaultLog.js
  85. 17 1
      src/enum/Actions.js
  86. 4 1
      src/enum/AssetTypeName.js
  87. 1 0
      src/enum/BillboardStatus.js
  88. 4 1
      src/enum/Codes.js
  89. 0 1
      src/index.js
  90. 823 4
      src/main.js
  91. 0 36
      src/video/ShaderCompiler.js
  92. 0 52
      src/video/ShaderProgram.js
  93. 0 50
      src/video/ShaderSources.js
  94. 0 88
      src/video/Texture.js
  95. 0 131
      src/video/YUVSurfaceShader.js
  96. 0 3
      src/video/h264.worker.js
  97. 0 208
      src/video/index.js
  98. 0 72
      src/video/test.js
  99. 0 107
      src/开发笔记.txt
  100. 0 0
      src/接口数据.txt

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 218
dist/assets/config.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 783 - 668
dist/index.html


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 1371
dist/libs/decoder copy.js


+ 39 - 6
dist/libs/decoder.js

@@ -1,3 +1,15 @@
+const WASM_Version = "h264"
+  , DECODER_VERSION = "v0.9.3"
+  , WASM_URLS = {
+    h264: "https://static.xverse.cn/wasm/v17/lib_ff264dec.js",
+    xv265: "https://static.xverse.cn/wasm/codec-release/h265-dec-sw-wasm/v-0-9-1/libxv265dec.js",
+    h265: ""
+}
+  , STUCK_STAGE_GOOD = 45
+  , STUCK_STAGE_WELL = 85
+  , STUCK_STAGE_FAIR = 125
+  , STUCK_STAGE_BAD = 165
+  , DECODER_PASSIVE_JITTER = 0;
 var decoder = `/* eslint-disable no-inner-declarations */
 /* eslint-disable default-case */
 /* eslint-disable no-restricted-globals */
@@ -136,6 +148,9 @@ if ('function' === typeof importScripts) {
 
     this.bufferIFrame = 0
     this.passiveJitterLength = 0
+
+    // for bypasser
+    this.decodeBypass = false
   }
 
   //refactor:
@@ -699,6 +714,12 @@ if ('function' === typeof importScripts) {
       return 1
     }
 
+    // ByPass Process
+    if (config.bypasserList.indexOf('DecodeStream') != -1) {
+      // do not decode frame any more
+      self.decoder.decodeBypass = true
+    }
+
     return 0
   }
 
@@ -948,6 +969,9 @@ if ('function' === typeof importScripts) {
     let ret = 0
     try {
       ret = Module._decodeData(0, 0, cacheBuffer, content_size, resultBuffer)
+      // currently only need to use flushDecoder for pano mode.
+      ret = Module._flushDecoder(0, 0, resultBuffer)
+
       // // console.log('[][Core][WASM] return value %s',ret)
       // if(ret!=0){
       //   // console.log('[][Core][WASM],-abcdefg-----> ', ret)
@@ -1017,11 +1041,12 @@ if ('function' === typeof importScripts) {
     const objData = {
       t: MessageEvent.PanoramaMessage,
       tileId: data.data.tileId,
-      uuid: data.data.uuid,
+      // uuid: data.data.uuid,
       data: yuv_data,
-      x: data.data.x,
-      y: data.data.y,
-      z: data.data.z,
+      metadata: data.data.metadata,
+      // x: data.data.x,
+      // y: data.data.y,
+      // z: data.data.z,
     }
     //TODO: remove debug
     if (this.startEmit) {
@@ -1064,7 +1089,7 @@ if ('function' === typeof importScripts) {
     const index = data.frameCnt % CACHE_BUF_LENGTH
     mediaArray[index].decode_ts = Date.now()
     var objData
-    if (content_size != 0) {
+    if (content_size != 0 && !self.decoder.decodeBypass) {
       // var date = Date.now()
       // var curDate = Date.now()
       // while (curDate - date < 100) {
@@ -1204,13 +1229,22 @@ if ('function' === typeof importScripts) {
         meta: data.meta,
         metadata: data.metadata,
       }
+      if (self.decoder.decodeBypass && content_size != 0) {
+        var first_available_buffer_null = YUVArray.shift()
+        var yuv_data_null = first_available_buffer_null.buffer
+        objData.data = yuv_data_null
+        objData.width = 1280 // TODO: do not hardcode
+        objData.height = 720 // TODO: do not hardcode
+      }
     }
     if (this.startEmit) {
       if (objData.data != null) {
+        objData.postTs = Date.now()
         self.postMessage(objData, [objData.data.buffer])
         send_out_buffer += 1
         this.receivedEmit++
       } else {
+        objData.postTs = Date.now()
         self.postMessage(objData)
         this.receivedEmit++
       }
@@ -1279,7 +1313,6 @@ if ('function' === typeof importScripts) {
   // console.log(getRandomInt(30));
 
   self.decoder = new Decoder()
-
   netArray = []
 
   var gTmpIdx = 0

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/libs/nipplejs.min.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 15
dist/libs/toastify-js


+ 12 - 12
dist/shader.js

@@ -9,7 +9,7 @@ uniform float bforceforceKeepContent;
  
 uniform sampler2D texture_video; 
 
-// \u7B49\u6BD4\u4F8B\u7F29\u653E\u753B\u9762\u5360\u6EE1\u5C4F\u5E55\uFF0C\u5B58\u5728\u5185\u5BB9\u7684\u4E22\u5931
+// 等比例缩放画面占满屏幕,存在内容的丢失
 vec2 equalScalingFitTvSize(vec2 uv, float tvWidthHeightScale, float mvWidthHeightScale)
 {
     if( tvWidthHeightScale > mvWidthHeightScale )
@@ -24,7 +24,7 @@ vec2 equalScalingFitTvSize(vec2 uv, float tvWidthHeightScale, float mvWidthHeigh
     return vec2( uv.x , uv.y);
 }
 
-// \u5F3A\u5236\u4FDD\u7559\u753B\u9762\u5185\u5BB9\uFF08\u5E26\u6709\u9ED1\u8FB9\uFF09
+// 强制保留画面内容(带有黑边)
 vec2 forceKeepContent(vec2 uv, float tvWidthHeightScale, float mvWidthHeightScale)
 {
     if( tvWidthHeightScale > mvWidthHeightScale )
@@ -45,7 +45,7 @@ void main()
     vec3 rgb; 
     vec3 color = vec3(0,0,0);
 
-    // \u4E00\u65E6\u8BBE\u7F6E\u4E86mvWidthHeightScale\uFF0C\u5C31\u4F1A\u89E6\u53D1\u7B49\u6BD4\u4F8B\u7F29\u653Eor\u5F3A\u5236\u4FDD\u5185\u5BB9
+    // 一旦设置了mvWidthHeightScale,就会触发等比例缩放or强制保内容
     if(tvWidthHeightScale > 0.0 && mvWidthHeightScale > 0.0)
     {
         if(bforceforceKeepContent > 0.0){
@@ -56,6 +56,11 @@ void main()
     }
     
     color = texture2D(texture_video, uv).rgb;
+
+    // 避免纯白的出现
+    color.r = clamp(color.r, 0.0, 0.99);
+    color.g = clamp(color.g, 0.0, 0.99);
+    color.b = clamp(color.b, 0.0, 0.99);
  
     if( uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0 )
     {
@@ -84,11 +89,6 @@ void main()
 `;
 
 
-
-
-
-
-
 var pureVideoFragment = `precision highp  float;
 
 varying vec3 ModelPos;
@@ -155,8 +155,8 @@ float ShadowCalculation(vec4 vPositionFromLight, sampler2D ShadowMap)
 // vec2 SampleTex(vec3 pt3d, vec2 widthHeight)
 vec2 SampleTex(vec3 pt3d)
 {
-    // // vec2 uv = vec2(  f/w*pt3d.x/pt3d.z, f/h*pt3d.y/pt3d.z ); // \u6A21\u578B\u53D8\u6362\u5230\u76F8\u673A\u5750\u6807\u7CFB\u4E0B
-    // vec2 uv = vec2(  focal/captureWidth*pt3d.x/pt3d.z, focal/captureHeight*pt3d.y/pt3d.z ); // \u6A21\u578B\u53D8\u6362\u5230\u76F8\u673A\u5750\u6807\u7CFB\u4E0B
+    // // vec2 uv = vec2(  f/w*pt3d.x/pt3d.z, f/h*pt3d.y/pt3d.z ); //模型变换到相机坐标系下
+    // vec2 uv = vec2(  focal/captureWidth*pt3d.x/pt3d.z, focal/captureHeight*pt3d.y/pt3d.z ); //模型变换到相机坐标系下 
     // uv.x = uv.x + 0.5;
     // uv.y = uv.y + 0.5;
     // return uv;
@@ -323,8 +323,8 @@ float ShadowCalculation(vec4 vPositionFromLight, sampler2D ShadowMap)
 vec2 SampleSphericalMap(vec3 pt3d)
 {
     vec2 uv = vec2( atan(-pt3d.z,pt3d.x), atan( pt3d.y, sqrt(pt3d.x*pt3d.x + pt3d.z * pt3d.z))); 
-    uv.x = 0.5 + uv.x * inv_2_PI ;     // yaw:   \u6C34\u5E73\u65B9\u5411 \uFF0C0 \u5230 360 \uFF0C \u5BF9\u5E948k\u7684\u5BBD  
-    uv.y = 0.5 + uv.y * inv_PI ;       // pitch: \u7AD6\u76F4\u65B9\u5411\uFF0C -64 \u5230 64 \uFF0C\u5BF9\u5E944k\u7684\u957F
+    uv.x = 0.5 + uv.x * inv_2_PI ;     // yaw:   水平方向 ,0 到 360 , 对应8k的宽
+    uv.y = 0.5 + uv.y * inv_PI ;       // pitch: 竖直方向, -64 到 64 ,对应4k的长
 
     return vec2(uv.x,uv.y);
 } 

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 168842
index.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 554 - 447
src/ActionsHandler.js


+ 128 - 144
src/BaseTable.js

@@ -2,29 +2,24 @@ import Logger from "./Logger.js"
 
 const logger = new Logger('db')
 export default class BaseTable {
-    constructor(dbName, dbVersion) {
-        this.db = null
-        this.isCreatingTable = !1
-        this.hasCleared = !1
-        this.dbName = dbName,
-        this.dbVersion = dbVersion
+    constructor(o, s) {
+        this.db = null;
+        this.isCreatingTable = !1;
+        this.hasCleared = !1;
+        this.dbName = o,
+        this.dbVersion = s
     }
-    async clearDataBase(e) {
-        if(!this.hasCleared){
-            e && (this.hasCleared = !0)
-            if(!window.indexedDB.databases){
-                return Promise.resolve()
-            }   
-            else{
-                return new Promise((resolve,reject)=>{
-                    const dBDeleteRequest = window.indexedDB.deleteDatabase(this.dbName);
-                    dBDeleteRequest.onsuccess = ()=>{
-                        resolve()
-                    },
-                    dBDeleteRequest.onerror = reject
-                })
+    async clearDataBase(o) {
+        return this.hasCleared || (o && (this.hasCleared = !0),
+        !window.indexedDB.databases) ? Promise.resolve() : new Promise((s,c)=>{
+            const _ = window.indexedDB.deleteDatabase(this.dbName);
+            _.onsuccess = ()=>{
+                s()
             }
+            ,
+            _.onerror = c
         }
+        )
     }
     tableName() {
         throw new Error("Derived class have to override 'tableName', and set a proper table name!")
@@ -36,176 +31,165 @@ export default class BaseTable {
         throw new Error("Derived class have to override 'index', and set a proper index name!")
     }
     async checkAndOpenDatabase() {
-        if(this.db){
-            return Promise.resolve(this.db)
-        }
-        else{
-            return new Promise((resolve,reject)=>{
-                const timeoutId = setTimeout(()=>{
-                    logger.info("wait db to open for", 200);
-                    if(this.db){
-                        resolve(this.db);
-                    }
-                    else{
-                        resolve(this.checkAndOpenDatabase());
-                    }
-                    clearTimeout(timeoutId)
-                }
-                , 200);
-                this.openDatabase(this.dbName, this.dbVersion || 1, ()=>{
-                    this.db && !this.isCreatingTable && resolve(this.db);
-                    logger.info(`successCallback called, this.db: ${!!this.db}, this.isCreatingStore: ${this.isCreatingTable}`);
-                    clearTimeout(timeoutId);
-                }
-                , ()=>{
-                    reject(new Error("Failed to open database!"));
-                    clearTimeout(timeoutId);
-                }
-                , ()=>{
-                    this.db && resolve(this.db);
-                    clearTimeout(timeoutId);
-                    logger.info(`successCallback called, this.db: ${!!this.db}, this.isCreatingStore: ${this.isCreatingTable}`);
-                }
-                )
+        return this.db ? Promise.resolve(this.db) : new Promise((o,s)=>{
+            const _ = setTimeout(()=>{
+                logger.warn("wait db to open for", 200),
+                this.db ? o(this.db) : o(this.checkAndOpenDatabase()),
+                clearTimeout(_)
+            }
+            , 200);
+            this.openDatabase(this.dbName, this.dbVersion || 1, ()=>{
+                this.db && !this.isCreatingTable && o(this.db),
+                logger.warn(`successCallback called, this.db: ${!!this.db}, this.isCreatingStore: ${this.isCreatingTable}`),
+                clearTimeout(_)
+            }
+            , ()=>{
+                s(new Error("Failed to open database!")),
+                clearTimeout(_)
+            }
+            , ()=>{
+                this.db && o(this.db),
+                clearTimeout(_),
+                logger.warn(`successCallback called, this.db: ${!!this.db}, this.isCreatingStore: ${this.isCreatingTable}`)
             }
             )
         }
+        )
     }
-
-    openDatabase(dbName, version, resolve, reject, complete) {
+    openDatabase(o, s, c, _, b) {
         if (this.isCreatingTable)
-        {
             return;
+        this.isCreatingTable = !0,
+        logger.warn({
+            database: o,
+            version: s
+        });
+        const k = window.indexedDB.open(o, s)
+          , j = this.tableName();
+        k.onsuccess = $=>{
+            this.db = k.result,
+            logger.warn(`IndexedDb ${o} is opened.`),
+            this.db.objectStoreNames.contains(j) && (this.isCreatingTable = !1),
+            c && c($)
         }
-        this.isCreatingTable = !0;
-        logger.info(dbName, version);
-        const dBOpenRequest = window.indexedDB.open(dbName, version);
-        const tableName = this.tableName();
-        dBOpenRequest.onsuccess = _event=>{
-            this.db = dBOpenRequest.result;
-            logger.info(`IndexedDb ${dbName} is opened.`);
-            this.db.objectStoreNames.contains(tableName) && (this.isCreatingTable = !1);
-            resolve && resolve(_event)
-        };
-        
-        dBOpenRequest.onerror = _event=>{
-            var u;
-            logger.error("Failed to open database", (u = _event == null ? void 0 : _event.srcElement) == null ? void 0 : u.error);
-            this.isCreatingTable = !1;
-            reject && reject(_event);
-            this.clearDataBase(!0);
-        };
-        
-        dBOpenRequest.onupgradeneeded = _event=>{
-            const u = _event.target.result;
-            const _index = this.index();
-            logger.info(`Creating table ${tableName}.`);
-            let h = u.objectStoreNames.contains(tableName);
-            if (h)
-                h = u.transaction([tableName], "readwrite").objectStore(tableName);
+        ,
+        k.onerror = $=>{
+            var _e;
+            logger.error("Failed to open database", (_e = $ == null ? void 0 : $.srcElement) == null ? void 0 : _e.error),
+            this.isCreatingTable = !1,
+            _ && _($),
+            this.clearDataBase(!0)
+        }
+        ,
+        k.onupgradeneeded = $=>{
+            const _e = $.target.result
+              , et = this.index();
+            logger.warn(`Creating table ${j}.`);
+            let tt = _e.objectStoreNames.contains(j);
+            if (tt)
+                tt = _e.transaction([j], "readwrite").objectStore(j);
             else {
-                const keyPath = this.keyPath();
-                h = u.createObjectStore(tableName, {
-                    keyPath: keyPath
+                const rt = this.keyPath();
+                tt = _e.createObjectStore(j, {
+                    keyPath: rt
                 })
             }
-
-            _index.map(f=>{
-                h.createIndex(f, f, {
+            et.map(rt=>{
+                tt.createIndex(rt, rt, {
                     unique: !1
                 })
-            });
-
-            this.isCreatingTable = !1;
-            logger.info(`Table ${tableName} opened`);
-            complete && complete(_event);
-        };
+            }
+            ),
+            this.isCreatingTable = !1,
+            logger.warn(`Table ${j} opened`),
+            b && b($)
+        }
     }
-    async add(e) {
-        const tableName = this.tableName();
-        const promise = (await this.checkAndOpenDatabase()).transaction([tableName], "readwrite").objectStore(tableName).add(e);
-        return new Promise(function(resolve, reject) {
-            promise.onsuccess = l=>{
-                resolve(l)
+    async add(o) {
+        const s = this.tableName()
+          , b = (await this.checkAndOpenDatabase()).transaction([s], "readwrite").objectStore(s).add(o);
+        return new Promise(function(k, j) {
+            b.onsuccess = $=>{
+                k($)
             }
             ,
-            promise.onerror = l=>{
-                var u;
-                logger.error((u = l.srcElement) == null ? void 0 : u.error),
-                reject(l)
+            b.onerror = $=>{
+                var _e;
+                logger.error((_e = $.srcElement) == null ? void 0 : _e.error),
+                j($)
             }
         }
         )
     }
-    async put(e) {
-        const tableName = this.tableName();
-        const promise = (await this.checkAndOpenDatabase()).transaction([tableName], "readwrite").objectStore(tableName).put(e);
-        return new Promise(function(resolve, reject) {
-            promise.onsuccess = l=>{
-                resolve(l)
+    async put(o) {
+        const s = this.tableName()
+          , b = (await this.checkAndOpenDatabase()).transaction([s], "readwrite").objectStore(s).put(o);
+        return new Promise(function(k, j) {
+            b.onsuccess = $=>{
+                k($)
             }
             ,
-            promise.onerror = l=>{
-                var u;
-                logger.error("db put error", (u = l.srcElement) == null ? void 0 : u.error),
-                reject(l)
+            b.onerror = $=>{
+                var _e;
+                logger.error("db put error", (_e = $.srcElement) == null ? void 0 : _e.error),
+                j($)
             }
         }
         )
     }
-    delete(e, resolve, reject) {
-        const tableName = this.tableName();
-        this.checkAndOpenDatabase().then(promise=>{
-            const s = promise.transaction([tableName], "readwrite").objectStore(tableName).delete(e);
-            s.onsuccess = resolve,
-            s.onerror = reject
+    delete(o, s, c) {
+        const _ = this.tableName();
+        this.checkAndOpenDatabase().then(b=>{
+            const j = b.transaction([_], "readwrite").objectStore(_).delete(o);
+            j.onsuccess = s,
+            j.onerror = c
         }
         )
     }
     update() {
-        this.checkAndOpenDatabase().then(promise=>{}
+        this.checkAndOpenDatabase().then(o=>{}
         )
     }
     async getAllKeys() {
-        const tableName = this.tableName()
-        const promise = await this.checkAndOpenDatabase();
-        return new Promise((resolve, reject)=>{
-            const a = promise.transaction([tableName], "readonly").objectStore(tableName).getAllKeys();
-            a.onsuccess = s=>{
-                resolve(s.target.result)
+        const o = this.tableName()
+          , s = await this.checkAndOpenDatabase();
+        return new Promise((c,_)=>{
+            const k = s.transaction([o], "readonly").objectStore(o).getAllKeys();
+            k.onsuccess = j=>{
+                c(j.target.result)
             }
             ,
-            a.onerror = s=>{
-                logger.error("db getAllKeys error", s),
-                reject(s)
+            k.onerror = j=>{
+                logger.error("db getAllKeys error", j),
+                _(j)
             }
         }
         )
     }
-    async query(keyName, filesrc) {
-        const tableName = this.tableName()
-        const promise = await this.checkAndOpenDatabase();
-        return new Promise((resolve, reject)=>{
-            const u = promise.transaction([tableName], "readonly").objectStore(tableName).index(keyName).get(filesrc);
-            u.onsuccess = function(c) {
-                var f;
-                const h = (f = c == null ? void 0 : c.target) == null ? void 0 : f.result;
-                resolve && resolve(h)
+    async query(o, s) {
+        const c = this.tableName()
+          , _ = await this.checkAndOpenDatabase();
+        return new Promise((b,k)=>{
+            const _e = _.transaction([c], "readonly").objectStore(c).index(o).get(s);
+            _e.onsuccess = function(et) {
+                var rt;
+                const tt = (rt = et == null ? void 0 : et.target) == null ? void 0 : rt.result;
+                b && b(tt)
             }
             ,
-            u.onerror = c=>{
-                logger.error("db query error", c),
-                reject(c)
+            _e.onerror = et=>{
+                logger.error("db query error", et),
+                k(et)
             }
         }
         )
     }
-    async sleep(e) {
-        return new Promise(t=>{
+    async sleep(o) {
+        return new Promise(s=>{
             setTimeout(()=>{
-                t("")
+                s("")
             }
-            , e)
+            , o)
         }
         )
     }

+ 199 - 64
src/BreathPoint.js

@@ -1,74 +1,209 @@
+import Logger from "./Logger.js"
+import ClickTargetName from "./enum/ClickTargetName.js"
+
+const logger = new Logger("breathPoint");
+
+function getBreathPointsConfig() {
+    return [{
+        position: {
+            x: -1025.77,
+            y: -48.29,
+            z: 126.89
+        },
+        id: "OfficeQiantai",
+        name: ClickTargetName.OfficeQiantai,
+        skinId: "10149",
+        maxVisibleRegion: 5,
+        imageUrl: "https://app-asset-1258211750.file.myqcloud.com/1/textures/qiantai.png",
+        width: 1.1,
+        height: .5,
+        textureName: "Qiantai"
+    }, {
+        position: {
+            x: -1194.1,
+            y: -532.33,
+            z: 89.75
+        },
+        id: "OfficeZhanting",
+        name: ClickTargetName.OfficeZhanting,
+        skinId: "10149",
+        maxVisibleRegion: 5,
+        imageUrl: "https://app-asset-1258211750.file.myqcloud.com/1/textures/zhanting.png",
+        width: 1.1,
+        height: .5,
+        textureName: "Zhanting"
+    }, {
+        position: {
+            x: 178,
+            y: -1308,
+            z: 30
+        },
+        id: "OfficeZixunqiang",
+        name: ClickTargetName.OfficeZixunqiang,
+        skinId: "10149",
+        notSandian: !0,
+        maxVisibleRegion: 5,
+        imageUrl: zixunqiangImg,
+        width: 1.1,
+        height: .5,
+        textureName: "Xingyunmanghe"
+    }, {
+        position: {
+            x: -4204,
+            y: -529,
+            z: 43
+        },
+        id: "OfficeTuring",
+        name: ClickTargetName.OfficeTuring,
+        skinId: "10149",
+        notSandian: !0,
+        maxVisibleRegion: 5,
+        imageUrl: turingImg,
+        width: 1.1,
+        height: .5,
+        textureName: "\u70B9\u51FB\u67E5\u770B"
+    }, {
+        position: {
+            x: -5580,
+            y: -527,
+            z: 37
+        },
+        id: "OfficeTuringlife",
+        name: ClickTargetName.OfficeTuringlife,
+        skinId: "10149",
+        notSandian: !0,
+        maxVisibleRegion: 5,
+        imageUrl: turingImg,
+        width: 1.1,
+        height: .5,
+        textureName: "\u70B9\u51FB\u67E5\u770B"
+    }, {
+        position: {
+            x: -1128.12,
+            y: -964.48,
+            z: 134.54
+        },
+        id: "OfficeZixunlan",
+        name: ClickTargetName.OfficeZixunlan,
+        skinId: "10149",
+        maxVisibleRegion: 5,
+        imageUrl: "https://app-asset-1258211750.file.myqcloud.com/1/textures/zixunlan.png",
+        width: 1.1,
+        height: .5,
+        textureName: "Zixunlan"
+    }, {
+        position: {
+            x: -803.9,
+            y: -1540,
+            z: 99.14
+        },
+        id: "OfficeBangongqu",
+        name: ClickTargetName.OfficeBangongqu,
+        skinId: "10149",
+        maxVisibleRegion: 5,
+        imageUrl: "https://app-asset-1258211750.file.myqcloud.com/1/textures/bangongqu.png",
+        width: 1.1,
+        height: .5,
+        textureName: "Bangongqu"
+    }, {
+        position: {
+            x: -80,
+            y: -1052.49,
+            z: 122.9
+        },
+        id: "OfficeZhaopin",
+        name: ClickTargetName.OfficeZhaopin,
+        skinId: "10149",
+        maxVisibleRegion: 5,
+        imageUrl: "https://app-asset-1258211750.file.myqcloud.com/1/textures/hr.png",
+        width: 1.1,
+        height: .5,
+        textureName: "Zhineng"
+    }]
+}
+
 export default class BreathPoint {
-    constructor(panoInfo) {
-        E(this, "_staticmesh");
-        E(this, "_id");
-        E(this, "_mat");
-        E(this, "_type");
-        E(this, "_maxVisibleRegion");
-        E(this, "_skinInfo");
-        E(this, "_scene");
-        E(this, "_isInScene");
-        const {mesh: xStaticMesh, id: id, position: position, rotation: rotation, mat: material, type: type="default", maxVisibleRegion: maxVisibleRegion=-1, scene: scene, skinInfo: skinInfo="default"} = panoInfo;
-        this._id = id;
-        xStaticMesh.mesh.position = ue4Position2Xverse(position);
-        xStaticMesh.mesh.rotation = ue4Rotation2Xverse(rotation);
-        this._staticmesh = xStaticMesh;
-        this._mat = material;
-        this._type = type;
-        this._maxVisibleRegion = maxVisibleRegion;
-        this._scene = scene;
-        this._skinInfo = skinInfo;
-        this._isInScene = !0;
-    }
-    get isInScene() {
-        return this._isInScene
-    }
-    get skinInfo() {
-        return this._skinInfo
-    }
-    get maxvisibleregion() {
-        return this._maxVisibleRegion
-    }
-    getMesh() {
-        return this._staticmesh
-    }
-    get mesh() {
-        return this._staticmesh.mesh
-    }
-    toggleVisibility(e) {
-        e == !0 ? this._staticmesh.show() : this._staticmesh.hide()
-    }
-    changePickable(e) {
-        this._staticmesh.mesh.isPickable = e
-    }
-    removeFromScene() {
-        if(this._isInScene){
-            this._staticmesh.mesh != null && this._scene.removeMesh(this._staticmesh.mesh)
-            this._isInScene = !1
+    constructor(o) {
+        this.visibilities = {};
+        this.room = o,
+        getBreathPointsConfig().forEach(c=>{
+            this.visibilities[c.name] = !0
         }
-    }
-    addToScene() {
-        if(this._isInScene == !1){
-            this._staticmesh.mesh != null && this._scene.addMesh(this._staticmesh.mesh);
-            this._isInScene = !0
+        ),
+        this.room.on("userAvatarLoaded", ()=>{
+            this.showBreathPointInSkin()
         }
-    }
-    dispose() {
-        let mesh = this._staticmesh.mesh
-        if(mesh != null){
-            mesh.dispose(!1, !1)
+        ),
+        this.room.on("skinChanged", ({skin: c})=>{
+            setTimeout(()=>{
+                const _ = c.id;
+                this.showBreathPointInSkin(_)
+            }
+            , 0)
         }
+        )
     }
-    set position(e) {
-        this._staticmesh.mesh.position = ue4Position2Xverse(e)
+    setVisibility(o, s=!1) {
+        Array.isArray(o) || (o = [o]),
+        o.forEach(c=>this.visibilities[c] = s),
+        this.showBreathPointInSkin()
     }
-    get position() {
-        return xversePosition2Ue4(this._staticmesh.mesh.position)
+    showBreathPointInSkin(o) {
+        o || (o = this.room.skin.id),
+        this.hideAll(),
+        getBreathPointsConfig().filter(c=>String(c.skinId) === o).forEach(async c=>{
+            if (!c.imageUrl || this.visibilities[c.name] === !1)
+                return;
+            let _;
+            try {
+                _ = await urlTransformer(c.imageUrl)
+            } catch (k) {
+                _ = c.imageUrl,
+                logger.error("urlTransformer error", k)
+            }
+            const b = this.room.breathPointManager.breathPoints.get(c.id);
+            if (b) {
+                b.toggleVisibility(!0);
+                return
+            }
+            this.room.breathPointManager.addBreathPoint({
+                id: c.id,
+                position: c.position,
+                spriteSheet: _,
+                rotation: c.rotation || {
+                    pitch: 0,
+                    yaw: 270,
+                    roll: 0
+                },
+                billboardMode: !0,
+                type: c.name,
+                spriteWidthNumber: c.notSandian ? 1 : 6,
+                spriteHeightNumber: c.notSandian ? 1 : 5,
+                maxVisibleRegion: c.maxVisibleRegion || 80,
+                width: c.width || 2.8 * 4,
+                height: c.height || 2 * 4
+            })
+        }
+        )
+    }
+    hideAll() {
+        getBreathPointsConfig().forEach(s=>{
+            this.room.breathPointManager.clearBreathPoints(s.name)
+        }
+        )
     }
-    set rotation(e) {
-        this._staticmesh.mesh.rotation = ue4Rotation2Xverse(e)
+    deleteBreathPoints(o) {
+        o.map(s=>this.room.breathPointManager.clearBreathPoints(s))
     }
-    get rotation() {
-        return xverseRotation2Ue4(this._staticmesh.mesh.rotation)
+    isMatched(o) {
+        const s = getBreathPointsConfig();
+        let c;
+        return (c = s.find(_=>_.id === o.id)) ? (this.room.emit("click", {
+            target: {
+                name: c.name,
+                id: c.id
+            }
+        }),
+        !0) : !1
     }
 }

+ 11 - 25
src/Broadcast.js

@@ -1,35 +1,21 @@
 import MessageHandleType from "./enum/MessageHandleType.js"
 import Logger from "./Logger.js"
 
-const logger = new Logger('Broadcast')
-
 export default class Broadcast{
-    constructor(xverseRoom, t) {
-        this.room = xverseRoom;
-        this.handlers = []
-        this.init(t)
-    }
-
-    init(t){
-        this.handlers.push(t)
+    constructor(o, s) {
+        this.room = o,
+        this.handlers = [];
+        this.handlers.push(s)
     }
-
-    async handleBroadcast(e) {
-        let t = null;
-        try {
-            t = JSON.parse(e.broadcastAction.data)
-        } catch (r) {
-            logger.error(r);
-            return
-        }
-    }
-    broadcast(e) {
-        const {data: t, msgType: r=MessageHandleType.MHT_FollowListMulticast, targetUserIds: n} = e;
+    broadcast(o) {
+        const {data: s, msgType: c=MessageHandleType.MHT_FollowListMulticast, targetUserIds: _, sampleRate: b=1} = o;
         return this.room.actionsHandler.broadcast({
-            data: t,
-            msgType: r,
-            targetUserIds: n
+            data: s,
+            msgType: c,
+            targetUserIds: _,
+            sampleRate: b
         })
     }
 }
 ;
+

+ 185 - 156
src/Camera.js

@@ -4,51 +4,93 @@ import EImageQuality from "./enum/EImageQuality.js"
 import Actions from "./enum/Actions.js"
 import Logger from "./Logger.js"
 
+const calNormVector = (d,o)=>{
+    let s = 0;
+    for (let _ = 0; _ < 3; ++_)
+        s = s + (o[_] - d[_]) * (o[_] - d[_]);
+    return s = Math.sqrt(s),
+    [(o[0] - d[0]) / s, (o[1] - d[1]) / s, (o[2] - d[2]) / s]
+}
+  , vectorCrossMulti = (d,o)=>{
+    const s = d[0]
+      , c = d[2]
+      , _ = o[0]
+      , b = o[2];
+    return s * b - c * _
+}
+
+function downloadFileByBase64(d, o) {
+    const s = dataURLtoBlob(d)
+      , c = URL.createObjectURL(s);
+    downloadFile(c, o)
+}
+function dataURLtoBlob(d) {
+    var k;
+    const o = d.split(",")
+      , s = (k = o[0].match(/:(.*?);/)) == null ? void 0 : k[1]
+      , c = atob(o[1]);
+    let _ = c.length;
+    const b = new Uint8Array(_);
+    for (; _--; )
+        b[_] = c.charCodeAt(_);
+    return new Blob([b],{
+        type: s
+    })
+}
+function downloadFile(d, o="screenShot.png") {
+    const s = document.createElement("a");
+    s.setAttribute("href", d),
+    s.setAttribute("download", o),
+    s.setAttribute("target", "_blank");
+    const c = document.createEvent("MouseEvents");
+    c.initEvent("click", !0, !0),
+    s.dispatchEvent(c)
+}
+
 const logger = new Logger('camera')
+const DEFAULT_COUNT = 3;
+
 export default class Camera extends EventEmitter {
-    constructor(e) {
+    constructor(s) {
         super();
-        this.initialFov = 0
-        this._state = CameraStates.Normal
-        this._person = Person.Third
-        this._cameraFollowing = !0
-        this._room = e
-    }
-
-    /*
-    checkPointOnLeftOrRight(e){
-        const t = ue4Position2Xverse(e);
-        if (!t || this.checkPointInView(e))
-        {
-            return;
-        }
-        const activeCamera = this._room.scene.activeCamera;
-        if (!activeCamera)
-        {
-            return;
+        this._state = CameraStates.Normal;
+        this._person = Person.Third;
+        this._room = null;
+        this.cameraStoped = !1;
+        this.lastCameraPose = null;
+        this.count = 0;
+        this.isMoving = !1;
+        this._cameraFollowing = 0;
+        this.checkPointOnLeftOrRight = s=>{
+            const c = ue4Position2Xverse(s);
+            if (!c || this.checkPointInView(s))
+                return;
+            const k = this._room.scene.activeCamera;
+            if (!k)
+                return;
+            const j = [k.target.x, k.target.y, k.target.z]
+              , $ = [k.position.x, k.position.y, k.position.z]
+              , {x: _e, y: et, z: tt} = c
+              , rt = calNormVector($, j)
+              , it = calNormVector($, [_e, et, tt]);
+            return vectorCrossMulti(rt, it) < 0 ? Direction.Right : Direction.Left
         }
-        const a = [activeCamera.target.x, activeCamera.target.y, activeCamera.target.z]
-          , s = [activeCamera.position.x, activeCamera.position.y, activeCamera.position.z]
-          , {x: l, y: u, z: c} = t
-          , h = calNormVector(s, a)
-          , f = calNormVector(s, [l, u, c]);
-        return vectorCrossMulti(h, f) < 0 ? Direction.Right : Direction.Left
-    }
 
-    checkPointInView(e,t,r){
-        const n = ue4Position2Xverse({
-            x: e,
-            y: t,
-            z: r
-        });
-        if (!n)
-            return !1;
-        for (let o = 0; o < 6; o++)
-            if (this._room.scene.frustumPlanes[o].dotCoordinate(n) < 0)
+        this.checkPointInView = ({x: s, y: c, z: _})=>{
+            const b = ue4Position2Xverse({
+                x: s,
+                y: c,
+                z: _
+            });
+            if (!b)
                 return !1;
-        return !0
+            for (let k = 0; k < 6; k++)
+                if (this._room.scene.frustumPlanes[k].dotCoordinate(b) < 0)
+                    return !1;
+            return !0
+        }
+        this._room = s
     }
-
     get person() {
         return this._person
     }
@@ -58,66 +100,55 @@ export default class Camera extends EventEmitter {
     get pose() {
         return this._room.currentClickingState.camera
     }
-    set cameraFollowing(e) {
-        logger.info("cameraFollowing setter", e),
+    set cameraFollowing(s) {
+        logger.info("cameraFollowing setter", s),
         this.setCameraFollowing({
-            isFollowHost: e
+            isFollowHost: s
         })
     }
     get cameraFollowing() {
         return this._cameraFollowing
     }
-
-    setCameraFollowing({isFollowHost: e}) {}
-    */
-
-    handleRenderInfo(e) {
-        const {cameraStateType} = e.renderInfo;
-        const sceneManager = this._room.sceneManager;
-
-        if(cameraStateType !== this._state) {
-            this._state = cameraStateType;
-            logger.debug("camera._state changed to", CameraStates[cameraStateType]);
-            
-            if(cameraStateType === CameraStates.CGView) {
-                sceneManager.cameraComponent.switchToCgCamera();
-                sceneManager.staticmeshComponent.getCgMesh().show();
-            } else {
-                sceneManager.cameraComponent.switchToMainCamera();
-                sceneManager.staticmeshComponent.getCgMesh().hide();
-            }
-
-            this.emit("stateChanged", { state: cameraStateType })
-        }
-        
-        if(this._room.isHost) return;
-
-        const {isFollowHost} = e.playerState;
-        if(!!isFollowHost !== this._cameraFollowing) {
-            this._cameraFollowing = !!isFollowHost;
-            this.emit("cameraFollowingChanged", { cameraFollowing: !!isFollowHost })
-        }
+    setCameraFollowing({isFollowHost: s}) {}
+    handleRenderInfo(s) {
+        const {cameraStateType: c} = s.renderInfo
+          , _ = this._room.sceneManager;
+        if (c !== this._state && (this._state = c,
+        logger.debug("camera._state changed to", CameraStates[c]),
+        c === CameraStates.CGView ? (_.cameraComponent.switchToCgCamera(),
+        _.staticmeshComponent.getCgMesh().show()) : (_.cameraComponent.switchToMainCamera(),
+        _.staticmeshComponent.getCgMesh().hide()),
+        this.emit("stateChanged", {
+            state: c
+        })),
+        this.isMoving = s.renderInfo.stillFrame === 0,
+        this._room.isHost)
+            return;
+        const {isFollowHost: b} = s.playerState;
+        !!b !== this._cameraFollowing && (this._cameraFollowing = !!b,
+        this.emit("cameraFollowingChanged", {
+            cameraFollowing: !!b
+        }))
     }
-    /*
-    setCameraState({state: state}) {
-        if (this._state === state) {
-            logger.warn(`You are already in ${CameraStates[state]} camera state`);
+    setCameraState({state: s}) {
+        if (this._state === s) {
+            logger.warn(`You are already in ${CameraStates[s]} camera state`);
             return
         }
-        state === CameraStates.Normal || this._state === CameraStates.ItemView && logger.warn("CloseUp camera state can only be triggerd by room internally")
+        s === CameraStates.Normal || this._state === CameraStates.ItemView && logger.warn("CloseUp camera state can only be triggerd by room internally")
     }
-    turnToFace({extra: e="", offset: t=0}) {
-        const r = {
+    turnToFace({extra: s="", offset: c=0}) {
+        const _ = {
             action_type: Actions.TurnToFace,
             turn_to_face_action: {
-                offset: t
+                offset: c
             }
         };
         return this.emit("viewChanged", {
-            extra: e
+            extra: s
         }),
         this._room.actionsHandler.sendData({
-            data: r
+            data: _
         })
     }
     isInDefaultView() {
@@ -126,102 +157,100 @@ export default class Camera extends EventEmitter {
             return
         }
         if (!this._room._currentClickingState)
-        {
-            logger.error("CurrentState should not be empty");
-            return !1;
-        }
-        const {camera: camera, player: player} = this._room._currentClickingState;
-        return Math.abs(player.angle.yaw - 180 - camera.angle.yaw) % 360 <= 4
+            return logger.error("CurrentState should not be empty"),
+            !1;
+        const {camera: s, player: c} = this._room._currentClickingState;
+        return Math.abs(c.angle.yaw - 180 - s.angle.yaw) % 360 <= 4
     }
-    
-    async screenShot({name: name, autoSave: autoSave=!1}) {
-        const engine = this._room.scene.getEngine()
-        const activeCamera = this._room.scene.activeCamera;
+    async screenShot({name: s, autoSave: c=!1, precision: _=1}) {
+        const b = this._room.scene.getEngine()
+          , k = this._room.scene.activeCamera;
         try {
-            this._room.sceneManager.setImageQuality(EImageQuality.high);
-            const promise = await CreateScreenshotAsync(engine, activeCamera, {
-                precision: 1
+            const j = await CreateScreenshotAsync(b, k, {
+                precision: _
             });
-            this._room.sceneManager.setImageQuality(EImageQuality.low);
-            autoSave === !0 && downloadFileByBase64(promise, name);
-            return Promise.resolve(promise)
-        } catch (error) {
-            this._room.sceneManager.setImageQuality(EImageQuality.low)
-            return Promise.reject(error)
-        }
-    }
-    changeToFirstPerson(e, t, r) {
-        const {camera: camera, player: player, attitude: attitude, areaName: areaName, pathName: pathName} = e;
-        return this._room.actionsHandler.requestPanorama({
-            camera: camera,
-            player: player,
-            attitude: attitude,
-            areaName: areaName,
-            pathName: pathName
-        }, t, r).then(()=>{
-            this._room.networkController.rtcp.workers.changePanoMode(!0);
-            const {position: u, angle: c} = player || {};
-            this._room.sceneManager.cameraComponent.changeToFirstPersonView({
-                position: u,
-                rotation: c
-            })
+            return c === !0 && downloadFileByBase64(j, s),
+            Promise.resolve(j)
+        } catch (j) {
+            return Promise.reject(j)
         }
-        )
     }
-    setPerson(e, t={
+    setPerson(s, c={
         camera: this._room._currentClickingState.camera,
-        player: this._room._currentClickingState.player
+        player: this._room._userAvatar.pose
     }) {
-        const startTime = Date.now();
-        return this._setPerson(e, t).then(n=>(logger.infoAndReportMeasurement({
-            tag: Person[e],
-            startTime: startTime,
+        const _ = Date.now();
+        return this._setPerson(s, c).then(b=>(logger.infoAndReportMeasurement({
+            tag: Person[s],
+            startTime: _,
             metric: "setPerson"
-        }),n)).catch(n=>(logger.infoAndReportMeasurement({
-            tag: Person[e],
-            startTime: startTime,
+        }),
+        b)).catch(b=>(logger.infoAndReportMeasurement({
+            tag: Person[s],
+            startTime: _,
             metric: "setPerson",
-            error: n
+            error: b
         }),
-        Promise.reject(n)))
+        Promise.reject(b)))
     }
-    _setPerson(e, t={
+    async _setPerson(s, c={
         camera: this._room._currentClickingState.camera,
-        player: this._room._currentClickingState.player
+        player: this._room._userAvatar.pose
     }) {
-        return e !== Person.First && e !== Person.Third ? Promise.reject("invalid person " + e) : !t.camera || !t.player ? Promise.reject(new ParamError("wrong camera or player")) : e === Person.First ? this._room.panorama.access({
-            camera: t.camera,
-            player: t.player,
+        if (s !== Person.First && s !== Person.Third)
+            return Promise.reject("invalid person " + s);
+        if (!c.camera || !c.player)
+            return Promise.reject(new ParamError("wrong camera or player"));
+        const _ = this._room.currentState.pathId
+          , b = this._room.skin.pathList
+          , k = await this._room.modelManager.findPath(this._room.skin.id, _)
+          , j = b.find($=>$.groupId === k.groupId && $.person === s && $.attitude === k.attitude);
+        return j ? s === Person.First ? this._room.panorama.access({
+            pathId: j == null ? void 0 : j.id,
+            camera: c.camera,
+            player: c.player,
             tag: "setPerson"
         }).then(()=>{
-            var o, a;
-            this._person = e,
-            (o = this._room._userAvatar) == null || o.hide();
-            const {position: r, angle: n} = ((a = this._room.currentClickingState) == null ? void 0 : a.camera) || {};
-            !r || !n || this._room.sceneManager.cameraComponent.changeToFirstPersonView({
-                position: r,
-                rotation: n
-            })
+            var $;
+            this._person = s,
+            ($ = this._room._userAvatar) == null || $.hide()
         }
         ) : this._room.panorama.exit({
-            camera: t.camera,
-            player: t.player
+            pathId: j == null ? void 0 : j.id,
+            camera: c.camera,
+            player: c.player
         }).then(()=>{
-            var r, n;
-            this._person = e,
-            (r = this._room._userAvatar) != null && r.xAvatar && ((n = this._room._userAvatar) == null || n.xAvatar.show())
+            var $, _e, et;
+            if (this._person = s,
+            ($ = this._room._userAvatar) != null && $.xAvatar) {
+                const tt = (_e = this._room._currentClickingState) == null ? void 0 : _e.camera;
+                tt && this._room.camera.setCameraPose(tt),
+                (et = this._room._userAvatar) == null || et.xAvatar.show()
+            }
         }
-        )
+        ) : Promise.reject(new ParamError("target person not found"))
     }
-    */
-    setCameraPose(cameraPose) {
+    setCameraPose(s) {
+        const c = JSON.stringify(this.lastCameraPose) === JSON.stringify(s);
+        c ? this.count++ : (this.count = 0,
+        this.cameraStoped = c),
+        c || this.emit("cameraMoving", s),
+        this.count >= DEFAULT_COUNT && c && (this.emit("cameraStoped", s),
+        this.cameraStoped = c,
+        this.count = 0),
+        this.lastCameraPose = s,
         this._room.sceneManager.cameraComponent.setCameraPose({
-            position: cameraPose.position,
-            rotation: cameraPose.angle
+            position: s.position,
+            rotation: s.angle
         })
     }
-    // setMainCameraRotationLimit(e) {
-    //     const {limitAxis: t, limitRotation: r} = e;
-    //     this._room.sceneManager.cameraComponent.setMainCameraRotationLimit(t, r)
-    // }
+    async setMainCameraRotationLimit(s) {
+        if (!this._room.panorama.actived)
+            return Promise.reject(new Error("panorama not actived when setMainCameraRotationLimit"));
+        const {limitAxis: c, limitRotation: _} = s;
+        await this._room.sceneManager.cameraComponent.setMainCameraRotationLimit(c, _)
+    }
+    removeMainCameraRotationLimit() {
+        this._room.sceneManager.cameraComponent.removeMainCameraRotationLimit()
+    }
 }

+ 39 - 85
src/CircularArray.js

@@ -1,38 +1,6 @@
-function add(i, e) {
-    return e == -1 && (e = 0),
-    i + e
-}
-
-function max(i, e) {
-    return Math.max(i, e)
-}
-
-function count_sd(i, e) {
-    function t(r, n) {
-        let o = 0;
-        return n == -1 ? o = 0 : o = (n - e) * (n - e),
-        r + o
-    }
-    return Math.sqrt(i.reduce(t, 0) / i.reduce(count_valid, 0)) || 0
-}
-
-function count_valid(i, e) {
-    let t = 0;
-    return e != -1 && (t = 1),
-    i + t
-}
-
-function count_less(i, e) {
-    function t(r, n) {
-        let o = 0;
-        return n != -1 && n < e && (o = 1),
-        r + o
-    }
-    return i.reduce(t, 0)
-}
 
 export default class CircularArray {
-    constructor(circularLength, t, lessThreshes) {
+    constructor(o, s, c) {
         this.sum = 0,
         this.incomingSum = 0,
         this.count = 0,
@@ -46,64 +14,50 @@ export default class CircularArray {
         this.countLess = !1,
         this.lessThreshes = [],
         this.incomingData = [],
-        this.circularData = Array(circularLength).fill(-1),
+        this.circularData = Array(o).fill(-1),
         this.circularPtr = 0,
-        this.circularLength = circularLength,
-        t && (this.countLess = !0,this.lessThreshes = lessThreshes)
-    }
-    add(e) {
-        if(this.circularData[this.circularPtr] != -1){
-            this.sum -= this.circularData[this.circularPtr]
-            if(Math.abs(this.circularData[this.circularPtr] - this.max) < .01) {
-                this.circularData[this.circularPtr] = -1
-                this.max = this.getMax(!1)
-            }
-        }
-        else{
-            this.count += 1
-        }
-
-        this.sum += e;
-        this.incomingSum += e;
-        this.incomingCount += 1;
-        this.max < e && (this.max = e);
-        this.incomingMax < e && (this.incomingMax = e);
-        this.circularData[this.circularPtr] = e;
-        this.circularPtr = (this.circularPtr + 1) % this.circularLength;
-        this.incomingData.push(e);
-        if(this.incomingData.length > this.circularLength){
-            this.clearIncoming();
-            this.incomingCount = 0;
-            this.incomingSum = 0;
-        }
-    }
-    computeAvg(e) {
-        return e.reduce(add, 0) / e.reduce(count_valid, 0) || 0
-    }
-    computeMax(e) {
-        return e.reduce(max, 0) || 0
-    }
-    computeThreshPercent(e) {
+        this.circularLength = o,
+        s && (this.countLess = !0,
+        this.lessThreshes = c)
+    }
+    add(o) {
+        o < 0 || (this.circularData[this.circularPtr] != -1 ? (this.sum -= this.circularData[this.circularPtr],
+        Math.abs(this.circularData[this.circularPtr] - this.max) < .01 && (this.circularData[this.circularPtr] = -1,
+        this.max = this.computeMax(this.circularData))) : this.count += 1,
+        this.sum += o,
+        this.incomingSum += o,
+        this.incomingCount += 1,
+        this.max < o && (this.max = o),
+        this.incomingMax < o && (this.incomingMax = o),
+        this.circularData[this.circularPtr] = o,
+        this.circularPtr = (this.circularPtr + 1) % this.circularLength,
+        this.incomingData.push(o),
+        this.incomingData.length > this.circularLength && (this.clearIncoming(),
+        this.incomingCount = 0,
+        this.incomingSum = 0))
+    }
+    computeAvg(o) {
+        return o.reduce(add, 0) / o.reduce(count_valid, 0) || 0
+    }
+    computeMax(o) {
+        return o.reduce(max, 0) || 0
+    }
+    computeThreshPercent(o) {
         if (this.countLess) {
-            const t = count_less(e, this.lessThreshes[0]) || 0
-              , r = count_less(e, this.lessThreshes[1]) || 0
-              , n = count_less(e, this.lessThreshes[2]) || 0
-              , o = count_less(e, this.lessThreshes[3]) || 0
-              , a = e.reduce(count_valid, 0);
-            return [t, r, n, o, a]
+            const s = count_less(o, this.lessThreshes[0]) || 0
+              , c = count_less(o, this.lessThreshes[1]) || 0
+              , _ = count_less(o, this.lessThreshes[2]) || 0
+              , b = count_less(o, this.lessThreshes[3]) || 0
+              , k = o.reduce(count_valid, 0);
+            return [s, c, _, b, k]
         } else
             return [0, 0, 0, 0, 0]
     }
     getAvg() {
-        const e = this.sum / this.count || 0
-          , t = this.computeAvg(this.circularData) || 0;
-        return Math.abs(e - t) > .01 && console.error("avg value mismatch: ", e, t),
-        this.computeAvg(this.circularData) || 0
-    }
-    getMax(e=!0) {
-        const t = this.computeMax(this.circularData) || 0;
-        return e && Math.abs(t - this.max) > .01 && console.error("max value mismatch: ", this.max, t),
-        this.computeMax(this.circularData) || 0
+        return this.sum / this.count || 0 || 0
+    }
+    getMax(o=!0) {
+        return this.max || 0
     }
     getStandardDeviation() {
         return count_sd(this.circularData, this.getAvg())

+ 25 - 24
src/DataStorage.js

@@ -1,44 +1,45 @@
-/*
-class DataStorage{
+
+export default class DataStorage{
     static _GetStorage() {
         try {
             return localStorage.setItem("test", ""),
             localStorage.removeItem("test"),
             localStorage
         } catch {
-            const e = {};
+            const o = {};
             return {
-                getItem: t=>{
-                    const r = e[t];
-                    return r === void 0 ? null : r
+                getItem: s=>{
+                    const c = o[s];
+                    return c === void 0 ? null : c
                 }
                 ,
-                setItem: (t,r)=>{
-                    e[t] = r
+                setItem: (s,c)=>{
+                    o[s] = c
                 }
             }
         }
     }
-    static ReadString(e, t) {
-        const r = this._Storage.getItem(e);
-        return r !== null ? r : t
+    static ReadString(o, s) {
+        const c = this._Storage.getItem(o);
+        return c !== null ? c : s
     }
-    static WriteString(e, t) {
-        this._Storage.setItem(e, t)
+    static WriteString(o, s) {
+        this._Storage.setItem(o, s)
     }
-    static ReadBoolean(e, t) {
-        const r = this._Storage.getItem(e);
-        return r !== null ? r === "true" : t
+    static ReadBoolean(o, s) {
+        const c = this._Storage.getItem(o);
+        return c !== null ? c === "true" : s
     }
-    static WriteBoolean(e, t) {
-        this._Storage.setItem(e, t ? "true" : "false")
+    static WriteBoolean(o, s) {
+        this._Storage.setItem(o, s ? "true" : "false")
     }
-    static ReadNumber(e, t) {
-        const r = this._Storage.getItem(e);
-        return r !== null ? parseFloat(r) : t
+    static ReadNumber(o, s) {
+        const c = this._Storage.getItem(o);
+        return c !== null ? parseFloat(c) : s
     }
-    static WriteNumber(e, t) {
-        this._Storage.setItem(e, t.toString())
+    static WriteNumber(o, s) {
+        this._Storage.setItem(o, s.toString())
     }
 };
-*/
+
+DataStorage._Storage = DataStorage._GetStorage();

+ 42 - 42
src/Debug.js

@@ -3,21 +3,21 @@ const BREATH_POINT_TYPE = "debugBreathPoint"
   , DEFAULT_SEARCH_RANGE = 1e3;
   
 export default class Debug {
-    constructor(e) {
-        E(this, "isShowNearbyBreathPoints", !1);
-        E(this, "isShowTapBreathPoints", !1);
-        E(this, "isSceneShading", !0);
-        E(this, "searchRange", DEFAULT_SEARCH_RANGE);
-        E(this, "nearbyBreathPointListening", !1);
-        E(this, "tapBreathPointListening", !1);
-        E(this, "dumpStreamTimer", 0);
-        this.room = e
+    constructor(o) {
+        this.isShowNearbyBreathPoints = !1;
+        this.isShowTapBreathPoints = !1;
+        this.isSceneShading = !0;
+        this.searchRange = DEFAULT_SEARCH_RANGE;
+        this.nearbyBreathPointListening = !1;
+        this.tapBreathPointListening = !1;
+        this.dumpStreamTimer = 0;
+        this.room = o
     }
     toggleStats() {
         return this.room.stats.isShow ? this.room.stats.hide() : this.room.stats.show()
     }
-    toggleNearbyBreathPoint(e=DEFAULT_SEARCH_RANGE) {
-        this.searchRange = e,
+    toggleNearbyBreathPoint(o=DEFAULT_SEARCH_RANGE) {
+        this.searchRange = o,
         this.isShowNearbyBreathPoints = !this.isShowNearbyBreathPoints,
         this.isShowNearbyBreathPoints ? (this.getPointsAndRender(),
         this.setupNearbyBreathPointListener()) : this.room.breathPointManager.clearBreathPoints(BREATH_POINT_TYPE)
@@ -26,16 +26,16 @@ export default class Debug {
         this.isShowTapBreathPoints = !this.isShowTapBreathPoints,
         this.isShowTapBreathPoints ? this.setupTapPointListener() : this.room.breathPointManager.clearBreathPoints(TAP_BREATH_POINT_TYPE)
     }
-    dumpStream(e, t=10 * 1e3) {
+    dumpStream(o, s=10 * 1e3) {
         if (this.dumpStreamTimer)
             throw new Error("dumpStream running");
         this.room.networkController.rtcp.workers.saveframe = !0,
         this.dumpStreamTimer = window.setTimeout(()=>{
             this.room.networkController.rtcp.workers.SaveMediaStream = !0,
             this.dumpStreamTimer = 0,
-            e && e()
+            o && o()
         }
-        , t)
+        , s)
     }
     toggleSceneshading() {
         this.isSceneShading = !this.isSceneShading,
@@ -43,28 +43,28 @@ export default class Debug {
     }
     setupTapPointListener() {
         this.tapBreathPointListening || (this.tapBreathPointListening = !0,
-        this.room.on("_coreClick", ({point: e})=>{
+        this.room.on("_coreClick", ({point: o})=>{
             this.isShowTapBreathPoints && this.renderTapBreathPoint({
                 id: "tapToint",
-                position: e
+                position: o
             })
         }
         ))
     }
-    renderTapBreathPoint({position: e, id: t}) {
-        let r;
-        if (r = this.room.breathPointManager.breathPoints.get(t)) {
-            r.position = e;
+    renderTapBreathPoint({position: o, id: s}) {
+        let c;
+        if (c = this.room.breathPointManager.breathPoints.get(s)) {
+            c.position = o;
             return
         }
         this.room.breathPointManager.addBreathPoint({
-            id: t,
-            position: e,
+            id: s,
+            position: o,
             type: TAP_BREATH_POINT_TYPE,
             size: .8,
             forceLeaveGround: !0,
             billboardMode: !0,
-            rotation: Math.abs(e.z) < 20 ? {
+            rotation: Math.abs(o.z) < 20 ? {
                 pitch: 90,
                 yaw: 0,
                 roll: 0
@@ -76,30 +76,30 @@ export default class Debug {
         })
     }
     setupNearbyBreathPointListener() {
-        var e;
+        var o;
         this.nearbyBreathPointListening || (this.nearbyBreathPointListening = !0,
-        (e = this.room._userAvatar) == null || e.on("stopMoving", ()=>{
+        (o = this.room._userAvatar) == null || o.on("stopMoving", ()=>{
             this.isShowNearbyBreathPoints && this.getPointsAndRender()
         }
         ))
     }
     async getPointsAndRender() {
-        var r, n;
-        const e = this.searchRange
-          , t = ((r = this.room._userAvatar) == null ? void 0 : r.position) && await this.getNeighborPoints({
-            point: (n = this.room._userAvatar) == null ? void 0 : n.position,
+        var c, _;
+        const o = this.searchRange
+          , s = ((c = this.room._userAvatar) == null ? void 0 : c.position) && await this.getNeighborPoints({
+            point: (_ = this.room._userAvatar) == null ? void 0 : _.position,
             containSelf: !0,
-            searchRange: e
+            searchRange: o
         }) || [];
-        this.room.breathPointManager.breathPoints.forEach(o=>{
-            !!t.find(s=>JSON.stringify(s) === o._id) || this.room.breathPointManager.clearBreathPoints(o._id)
+        this.room.breathPointManager.breathPoints.forEach(b=>{
+            !!s.find(j=>JSON.stringify(j) === b._id) || this.room.breathPointManager.clearBreathPoints(b._id)
         }
         ),
-        t.forEach(o=>{
-            const a = o.breakPointId + "" // JSON.stringify(o);
-            this.room.breathPointManager.breathPoints.get(a) || this.room.breathPointManager.addBreathPoint({
-                id: a,
-                position: o.position,
+        s.forEach(b=>{
+            const k = JSON.stringify(b);
+            this.room.breathPointManager.breathPoints.get(k) || this.room.breathPointManager.addBreathPoint({
+                id: k,
+                position: b,
                 type: BREATH_POINT_TYPE,
                 rotation: {
                     pitch: 90,
@@ -111,12 +111,12 @@ export default class Debug {
         }
         )
     }
-    getNeighborPoints(e) {
-        const {point: t, containSelf: r=!1, searchRange: n=500} = e;
+    getNeighborPoints(o) {
+        const {point: s, containSelf: c=!1, searchRange: _=500} = o;
         return this.room.actionsHandler.getNeighborPoints({
-            point: t,
-            containSelf: r,
-            searchRange: n
+            point: s,
+            containSelf: c,
+            searchRange: _
         })
     }
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 465 - 491
src/EngineProxy.js


+ 7 - 0
src/Error/CodeErrorMap.js

@@ -32,6 +32,9 @@ import ServerRateLimitError from "./ServerRateLimitError.js"
 import DoActionBlockedError from "./DoActionBlockedError.js"
 import ActionMaybeDelayError from "./ActionMaybeDelayError.js"
 import ActionResponseTimeoutError from "./ActionResponseTimeoutError.js"
+import ConnectingAlreadyError from "./ConnectingAlreadyError.js"
+import UnReachableError from "./UnReachableError.js"
+import AbnormalDataStructureError from "./AbnormalDataStructureError.js"
 
 const CodeErrorMap = {
     1001: ParamError,
@@ -48,6 +51,7 @@ const CodeErrorMap = {
     1012: ActionBlockedError,
     1013: PreloadCanceledError,
     1014: FrequencyLimitError,
+    1015: ConnectingAlreadyError,
     2e3: UsersUpperLimitError,
     2001: RoomsUpperLimitError,
     2002: ServerParamError,
@@ -66,7 +70,10 @@ const CodeErrorMap = {
     2019: TicketExpireError,
     2020: ServerRateLimitError,
     2333: DoActionBlockedError,
+    2335: UnReachableError,
     2334: ActionMaybeDelayError,
+    2998: AbnormalDataStructureError,
     2999: ActionResponseTimeoutError
 };
+
 export default CodeErrorMap

+ 12 - 59
src/Error/XverseError.js

@@ -1,9 +1,7 @@
-import Codes from "../enum/Codes.js"
-
-export default class XverseError extends Error {
-    constructor(e, t) {
-        super(t);
-        this.code = e
+export default class XverseError extends Error{
+    constructor(o, s) {
+        super(s),
+        this.code = o
     }
     toJSON() {
         return {
@@ -14,57 +12,12 @@ export default class XverseError extends Error {
     toString() {
         if (Object(this) !== this)
             throw new TypeError;
-        let t = this.name;
-        t = t === void 0 ? "Error" : String(t);
-        let r = this.message;
-        r = r === void 0 ? "" : String(r);
-        const n = this.code;
-        return r = n === void 0 ? r : n + "," + r,
-        t === "" ? r : r === "" ? t : t + ": " + r
+        let s = this.name;
+        s = s === void 0 ? "Error" : String(s);
+        let c = this.message;
+        c = c === void 0 ? "" : String(c);
+        const _ = this.code;
+        return c = _ === void 0 ? c : _ + "," + c,
+        s === "" ? c : c === "" ? s : s + ": " + c
     }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+}

+ 35 - 36
src/EventsController.js

@@ -6,48 +6,47 @@ import Logger from "./Logger.js"
 const logger = new Logger('eventsController')
 
 export default class EventsController {
-    constructor(e) {
-        E(this, "staticmeshEvent");
-        E(this, "rotationEvent");
-        E(this, "resize", ()=>{
-            this.room.sceneManager.cameraComponent.cameraFovChange(this.room.sceneManager.yuvInfo)
-        }
-        );
-        E(this, "clickEvent", e=>{
-            const {point: t, name: r, type: n, id: o} = e;
-            logger.debug("pointEvent", e),
+    constructor(o) {
+        this.staticmeshEvent = null;
+        this.rotationEvent = null;
+        this.resize = ()=>{
+            this.room.panorama.actived || this.room.sceneManager.cameraComponent.cameraFovChange(this.room.sceneManager.yuvInfo)
+        };
+
+        this.clickEvent = o=>{
+            const {point: s, name: c, type: _, id: b} = o;
+            logger.debug("pointEvent", o),
             this.room.proxyEvents("pointTap", {
-                point: t,
-                meshName: r,
-                type: n,
-                id: o
+                point: s,
+                meshName: c,
+                type: _,
+                id: b
             }),
-            this.room.proxyEvents("_coreClick", e)
-        }
-        );
-        E(this, "longPressEvent", e=>{
-            this.room.proxyEvents("_corePress", e)
-        }
-        );
-        E(this, "handleActionResponseTimeout", ({error: e, event: t})=>{
+            this.room.proxyEvents("_coreClick", o)
+        };
+
+        this.longPressEvent = o=>{
+            this.room.proxyEvents("_corePress", o)
+        };
+
+        this.handleActionResponseTimeout = ({error: o, event: s})=>{
             this.room.proxyEvents("actionResponseTimeout", {
-                error: e,
-                event: t
+                error: o,
+                event: s
             })
-        }
-        );
-        E(this, "handleNetworkStateChange", e=>{
-            const {state: t, count: r} = e;
-            t == "reconnecting" ? this.room.proxyEvents("reconnecting", {
-                count: r || 1
-            }) : t === "reconnected" ? (this.room.networkController.rtcp.workers.reset(),
+        };
+
+        this.handleNetworkStateChange = o=>{
+            const {state: s, count: c} = o;
+            s == "reconnecting" ? this.room.proxyEvents("reconnecting", {
+                count: c || 1
+            }) : s === "reconnected" ? (this.room.networkController.rtcp.workers.reset(),
             this.room.proxyEvents("reconnected"),
-            this.room.afterReconnected()) : t === "disconnected" && this.room.proxyEvents("disconnected")
-        }
-        );
-        this.room = e,
+            this.room.afterReconnected()) : s === "disconnected" && this.room.proxyEvents("disconnected")
+        };
+        this.room = o,
         this.staticmeshEvent = new StaticMeshEvent(this.room.sceneManager),
-        this.rotationEvent = new RotationEvent(e)
+        this.rotationEvent = new RotationEvent(o)
     }
     bindEvents() {
         window.addEventListener("orientationchange"in window ? "orientationchange" : "resize", this.resize),

+ 92 - 90
src/EventsManager.js

@@ -8,110 +8,112 @@ const logger = new Logger('EventsManager')
 export default class EventsManager extends EventEmitter {
     constructor() {
         super(...arguments);
-        this.events = new Map
-        this.specialEvents = new Map
+        this.events = new Map;
+        this.specialEvents = new Map;
     }
 
-    remove(traceId, code, signal, needDelete) 
-    {
-        if (this.specialEvents.has(traceId) && !needDelete && code === Codes.Success) return;
-
-        this.events.get(traceId) && (
-            this.emit(traceId, {code, data:signal}),
-            this.events.delete(traceId),
-            this.specialEvents.delete(traceId)
-        )
-
-        // todo 写死数据纠正
-        // if (this.specialEvents.has(this.traceId) && !needDelete && code === Codes.Success) return;
-
-        // this.events.get(this.traceId) && (
-        //     this.emit(this.traceId, {code, data:signal}),
-        //     this.events.delete(this.traceId),
-        //     this.specialEvents.delete(this.traceId)
-        // )
+    remove(s, c, _, b) {
+        if (this.specialEvents.has(s) && !b && c === Codes.Success)
+            return;
+        this.events.get(s) && (this.emit(s, {
+            code: c,
+            data: _
+        }),
+        this.events.delete(s),
+        this.specialEvents.delete(s))
     }
-
-    async track(e, t) 
-    {
-        const traceId = e.traceId;
-        // this.traceId = traceId  // todo 写死数据纠正
-
-        this.emitTraceIdToDecoder(e);
-
-        const { sampleRate, noReport=!1, special } = t || {};
-        if (sampleRate && Math.random() > sampleRate) return Promise.resolve();
-        const s = Actions[e.event] + "Action"
-        const tag = e.tag;
-
-        // 暂存traceId
-        this.events.set(traceId, !0),
-        special && this.specialEvents.set(traceId, !0);
-        
-        const startTime = Date.now();
-        let c = null;
-        return new Promise((resolve, reject) => 
-        {
-            if (noReport)
-                return this.off(traceId),
-                    this.events.delete(traceId),
-                    resolve(void 0);
-
-            // 移除traceId。events.delete在emit之后执行
-            this.on(traceId, ({ code, data, msg }) => 
-            {
-                if (code === Codes.Success)
-                    resolve(data),
-                    this.off(traceId),
-                    logger.infoAndReportMeasurement({ type: s, traceId, tag, extraData: e.extra });
+    async track(s, c) {
+        const _ = s.traceId
+          , {sampleRate: b=1, noReport: k=!1, special: j} = c || {}
+          , $ = Actions[s.event] + "Action"
+          , _e = s.tag;
+        this.events.set(_, !0),
+        j && this.specialEvents.set(_, !0);
+        const et = Date.now();
+        let tt = null;
+        return new Promise((rt,it)=>{
+            if (k)
+                return this.off(_),
+                this.events.delete(_),
+                rt(void 0);
+            this.on(_, ({code: at, data: ot, msg: st})=>{
+                if (at === Codes.Success)
+                    rt(ot),
+                    this.off(_),
+                    Math.random() < b && logger.infoAndReportMeasurement({
+                        metric: $,
+                        tag: _e,
+                        extra: s.extra,
+                        startTime: et,
+                        traceId: _
+                    });
                 else {
-                    if (code === Codes.ActionMaybeDelay) return;
-                    if (code === Codes.DoActionBlocked && e.event === Actions.Rotation) {
-                        logger.debug(s + " response code: " + code);
+                    if (at === Codes.ActionMaybeDelay)
+                        return;
+                    if (at === Codes.DoActionBlocked && s.event === Actions.Rotation) {
+                        logger.debug($ + " response code: " + at);
                         return
                     }
-                    const CodeError = util.getErrorByCode(code)
-                      , error = new CodeError(msg);
-                    this.off(traceId),
-                    reject(error),
-                    this.emit("actionResponseError", { error, event: e, tag }),
-                    logger.infoAndReportMeasurement({ type: s, traceId, tag, error, extraData: e.extra })
+                    const lt = getErrorByCode(at)
+                      , ut = new lt(st);
+                    this.off(_),
+                    it(ut),
+                    this.emit("actionResponseError", {
+                        error: ut,
+                        event: s,
+                        tag: _e
+                    }),
+                    logger.infoAndReportMeasurement({
+                        metric: $,
+                        tag: _e,
+                        extra: s.extra,
+                        error: ut,
+                        startTime: et,
+                        traceId: _
+                    })
                 }
-            });
-
-            // 超时报错
-            const time = e.timeout || 2e3;
-            c = window.setTimeout(() => 
-            {
-                if (c && clearTimeout(c), !this.events.get(traceId)) return;
-
-                const error = new ActionResponseTimeoutError(`${s} timeout in ${time}ms`);
-                this.emit("actionResponseTimeout", { error, event: e, tag }),
-                reject(error),
-                this.events.delete(traceId),
-                this.off(traceId),
-                logger.infoAndReportMeasurement({ type: s, traceId, tag, error, extraData: e.extra })
-            }, time)
-        })
+            }
+            );
+            const nt = s.timeout || 2e3;
+            tt = window.setTimeout(()=>{
+                if (tt && clearTimeout(tt),
+                !this.events.get(_))
+                    return;
+                const at = new ActionResponseTimeoutError(`${$} timeout in ${nt}ms`);
+                this.emit("actionResponseTimeout", {
+                    error: at,
+                    event: s,
+                    tag: _e
+                }),
+                it(at),
+                this.events.delete(_),
+                this.off(_),
+                logger.infoAndReportMeasurement({
+                    metric: $,
+                    tag: _e,
+                    extra: s.extra,
+                    error: at,
+                    startTime: et,
+                    traceId: _
+                })
+            }
+            , nt)
+        }
+        )
     }
-
-    emitTraceIdToDecoder(e) {
-        if (
-            e.event === Actions.Rotation || 
-            e.event === Actions.Clicking || 
-            e.event === Actions.GetOnVehicle || 
-            e.event === Actions.GetOffVehicle
-        ) {
-            const t = {
+    emitTraceIdToDecoder(s, c) {
+        if (s === Actions.Rotation || s === Actions.Clicking || s === Actions.GetOnVehicle || s === Actions.GetOffVehicle || s === Actions.JoystickLocal) {
+            const _ = {
                 [Actions.Rotation]: "Rotation",
                 [Actions.GetOnVehicle]: "GetOnVehicle",
                 [Actions.GetOffVehicle]: "GetOffVehicle",
-                [Actions.Clicking]: "MoveTo"
+                [Actions.Clicking]: "MoveTo",
+                [Actions.JoystickLocal]: "Joystick"
             };
             this.emit("traceId", {
-                traceId: e.traceId,
+                traceId: c,
                 timestamp: Date.now(),
-                event: t[e.event]
+                event: _[s]
             })
         }
     }

+ 9 - 14
src/Heartbeat.js

@@ -3,18 +3,13 @@ import Logger from "./Logger.js"
 const logger = new Logger('heartbeat')
 
 export default class Heartbeat {
-    constructor(e) {
-        E(this, "_interval", null);
-        E(this, "ping", ()=>{
-            const e = Date.now().toString();
-            this.handler.ping(e)
-        }
-        );
-        this.handler = e
-    }
-    ping(){
-        const e = Date.now().toString();
-        this.handler.ping(e)
+    constructor(o) {
+        this._interval = null;
+        this.ping = ()=>{
+            const o = Date.now().toString();
+            this.handler.ping(o)
+        };
+        this.handler = o
     }
     start() {
         this.stop(),
@@ -25,7 +20,7 @@ export default class Heartbeat {
         logger.debug("stop heartbeat"),
         this._interval && window.clearInterval(this._interval)
     }
-    pong(e, t) {
-        !e || typeof e == "string" && this.handler.pong(Date.now() - Number(e), t)
+    pong(o, s) {
+        !o || typeof o == "string" && this.handler.pong(Date.now() - Number(o), s)
     }
 }

+ 85 - 141
src/Http.js

@@ -1,151 +1,95 @@
 import Xverse from "./Xverse.js"
-import {modelTable} from "./ModelTable.js"
+import AxiosCanceler from "./AxiosCanceler.js"
 import Logger from "./Logger.js"
 
 const logger = new Logger('Http')
-const isIndexedDbSupported = ()=>(window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB) !== void 0
-const dataURItoBlob = i=>{
-    let e;
-    i.split(",")[0].indexOf("base64") >= 0 ? e = atob(i.split(",")[1]) : e = unescape(i.split(",")[1]);
-    const t = i.split(",")[0].split(":")[1].split(";")[0]
-      , r = new Uint8Array(e.length);
-    for (let o = 0; o < e.length; o++)
-        r[o] = e.charCodeAt(o);
-    return new Blob([r],{
-        type: t
-    })
-}
 
-export default class Http extends EventEmitter {
-    async get({url: e, useIndexedDb: t=!1, timeout: r=15e3, key: n, isOutPutObjectURL: o=!0}) {
-        if (Xverse.NO_CACHE !== void 0 && (t = !Xverse.NO_CACHE),
-        t)
-            if (isIndexedDbSupported()) {
-                window.performance.now();
-                let a = null;
-                try {
-                    a = await modelTable.query("url", e)
-                } catch (s) {
-                    return logger.debug(s),
-                    logger.warn("cache query error", e),
-                    Promise.resolve(e)
-                }
-                if (a && a.model) {
-                    const s = dataURItoBlob(a.model)
-                      , l = Promise.resolve(o ? URL.createObjectURL(s) : s);
-                    return window.performance.now(),
-                    l
-                } else
-                    return this.request({
-                        url: e,
-                        timeout: r,
-                        contentType: "blob",
-                        key: n
-                    }).then(async s=>{
-                        const l = await blobToDataURI(s.response);
-                        try {
-                            await modelTable.put({
-                                url: e,
-                                model: l
-                            })
-                        } catch (u) {
-                            logger.warn("unable to add data to indexedDB", u)
-                        }
-                        return Promise.resolve(o ? URL.createObjectURL(s.response) : s.response)
-                    }
-                    )
-            } else
-                return this.request({
-                    url: e,
-                    timeout: r,
-                    contentType: "blob",
-                    key: n
-                }).then(a=>{
-                    const s = a.response;
-                    return Promise.resolve(o ? URL.createObjectURL(s) : s)
-                }
-                ).catch(a=>Promise.reject(a));
-        else
-            return this.request({
-                url: e,
-                timeout: r,
-                key: n
-            }).then(a=>a.getResponseHeader("content-type") === "application/json" ? Promise.resolve(JSON.parse(a.responseText)) : Promise.resolve(a.responseText))
+export default class Http {
+    constructor() {
+        this.requestParams = o=>({
+            ...o.params
+        });
+        this.requestConstant = ()=>({
+            x_nounce: this.randomString(),
+            x_timestamp: new Date().getTime(),
+            x_os: "web"
+        });
+        this.instatnce = axios.create(),
+        this.canceler = new AxiosCanceler
+    }
+    get(o) {
+        return this.request({
+            ...o,
+            method: "GET"
+        })
+    }
+    post(o) {
+        return this.request({
+            ...o,
+            method: "POST"
+        })
     }
-    request(e) {
-        const {timeout: t=3e4, contentType: r, key: n, onRequestStart: o} = e
-          , {url: a} = e;
-        return new Promise((s,l)=>{
-            window.performance.now();
-            const u = new XMLHttpRequest;
-            r && (u.responseType = r),
-            u.timeout = t,
-            u.addEventListener("readystatechange", ()=>{
-                if (u.readyState == 4) {
-                    if (u.status == 200)
-                        return window.performance.now(),
-                        this.emit("loadend", {
-                            message: `request ${a} load success`
-                        }),
-                        s(u);
-                    {
-                        const c = `Unable to load the request ${a}`;
-                        return this.emit("error", {
-                            message: c
-                        }),
-                        logger.error(c),
-                        l(c)
-                    }
-                }
-            }
-            ),
-            o && o(u),
-            u.open("GET", a),
-            u.send()
+    request(o) {
+        const {url: s, timeout: c=1e4, method: _, key: b, beforeRequest: k, responseType: j, data: $} = o;
+        let {retry: _e=0} = o;
+        const et = this.transformUrlHook(s)
+          , tt = this.canceler.addPending(s);
+        k && isFunction(k) && k(o);
+        const rt = this.requestParams(o);
+        let it = {
+            url: et,
+            method: _,
+            timeout: c,
+            cancelToken: tt,
+            responseType: j,
+            params: rt
+        };
+        _ === "POST" && (it = {
+            data: $,
+            ...it
+        });
+        const nt = Date.now()
+          , at = ()=>this.instatnce.request(it).then(ot=>(b && logger.infoAndReportMeasurement({
+            metric: "http",
+            startTime: nt,
+            extra: s,
+            group: "http",
+            tag: b
+        }),
+        this.canceler.removeCancelToken(s),
+        ot)).catch(ot=>{
+            const st = axios.isCancel(ot);
+            return _e > 0 && !st ? (_e--,
+            logger.warn(`request ${s} retry, left retry count`, _e),
+            at()) : (logger.infoAndReportMeasurement({
+                metric: "http",
+                startTime: nt,
+                error: ot,
+                extra: {
+                    url: s,
+                    isCanceled: st
+                },
+                tag: b,
+                group: "http"
+            }),
+            this.canceler.removeCancelToken(s),
+            Promise.reject(ot))
         }
-        )
+        );
+        return at()
+    }
+    transformUrlHook(o) {
+        return o
+    }
+    randomString() {
+        let o = "";
+        const s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+          , c = s.length;
+        for (let _ = 0; _ < 8; _++)
+            o += s.charAt(Math.floor(Math.random() * c));
+        return o
     }
 }
 
-// const http = new Http();
-// export { http };
-
-// const http = new Http
-//   , isIndexedDbSupported = ()=>(window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB) !== void 0
-//   , blobToDataURI = async i=>new Promise((e,t)=>{
-//     const r = new FileReader;
-//     r.readAsDataURL(i),
-//     r.onload = function(n) {
-//         var o;
-//         e((o = n.target) == null ? void 0 : o.result)
-//     }
-//     ,
-//     r.onerror = function(n) {
-//         t(n)
-//     }
-// }
-// )
-//   , dataURItoBlob = i=>{
-//     let e;
-//     i.split(",")[0].indexOf("base64") >= 0 ? e = atob(i.split(",")[1]) : e = unescape(i.split(",")[1]);
-//     const t = i.split(",")[0].split(":")[1].split(";")[0]
-//       , r = new Uint8Array(e.length);
-//     for (let o = 0; o < e.length; o++)
-//         r[o] = e.charCodeAt(o);
-//     return new Blob([r],{
-//         type: t
-//     })
-// }
-//   , urlMap = new Map
-//   , urlTransformer = async(i,e=!1)=>typeof i != "string" ? (console.warn("url transformer error", i),
-// i) : i.startsWith("blob:") ? i : e ? http.get({
-//     url: i,
-//     useIndexedDb: !0,
-//     key: "url",
-//     isOutPutObjectURL: !1
-// }) : urlMap.has(i) ? urlMap.get(i) : http.get({
-//     url: i,
-//     useIndexedDb: !0,
-//     key: "url"
-// }).then(t=>(urlMap.set(i, t),
-// t));
+const http = new Http();
+export { http };

+ 0 - 95
src/Http1.js

@@ -1,95 +0,0 @@
-import AxiosCanceler from "./AxiosCanceler"
-
-import Logger from "./Logger.js"
-
-const logger = new Logger('Http')
-class Http1 extends EventEmitter {
-    constructor() {
-        super()
-        this.instatnce = axios.create();
-        this.canceler = new AxiosCanceler;
-    }
-
-    requestConstant(){
-        return {
-            x_nounce: this.randomString(),
-            x_timestamp: new Date().getTime(),
-            x_os: "web"
-        }
-    }
-
-    requestParams(e){
-        return oe({}, e.params)
-    }
-
-    get(e) {
-        return this.request(le(oe({}, e), {
-            method: "GET"
-        }))
-    }
-    post(e) {
-        return this.request(le(oe({}, e), {
-            method: "POST"
-        }))
-    }
-    request(e) {
-        const {url: t, timeout: r=1e4, method: n, key: o, beforeRequest: a, responseType: s, data: l} = e;
-        let {retry: u=0} = e;
-        const c = this.patchUrl(t)
-          , h = this.canceler.addPending(t);
-        a && isFunction(a) && a(e);
-        const f = this.requestParams(e);
-        let d = {
-            url: c,
-            method: n,
-            timeout: r,
-            cancelToken: h,
-            responseType: s,
-            params: f
-        };
-        n === "POST" && (d = oe({
-            data: l
-        }, d));
-        const _ = Date.now()
-          , g = ()=>this.instatnce.request(d).then(m=>(o && logger.infoAndReportMeasurement({
-            type: "http",
-            extraData: t,
-            group: "http",
-            tag: o
-        }),
-        this.canceler.removeCancelToken(t),
-        m)).catch(m=>{
-            const v = axios.isCancel(m);
-            return u > 0 && !v ? (u--,
-            logger.warn(`request ${t} retry, left retry count`, u),
-            g()) : (logger.infoAndReportMeasurement({
-                type: "http",
-                error: m,
-                extraData: {
-                    url: t,
-                    isCanceled: v
-                },
-                tag: o,
-                group: "http"
-            }),
-            this.canceler.removeCancelToken(t),
-            Promise.reject(m))
-        }
-        );
-        return g()
-    }
-    patchUrl(e) {
-        return e
-    }
-    randomString() {
-        let e = "";
-        const t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
-          , r = t.length;
-        for (let n = 0; n < 8; n++)
-            e += t.charAt(Math.floor(Math.random() * r));
-        return e
-    }
-}
-
-const http1 = new Http1();
-export { http1 };

+ 0 - 147
src/Http2.js

@@ -1,147 +0,0 @@
-import {modelTable} from "./ModelTable.js"
-import Logger from "./Logger.js"
-
-const logger = new Logger('Http')
-class Http2 extends EventEmitter {
-    async get({url: e, useIndexedDb: t=!1, timeout: r=1e4, key: n}) {
-        if (t)
-            if (isIndexedDbSupported$1()) {
-                const o = window.performance.now();
-                let a = null;
-                try {
-                    a = await modelTable.models.where("name").equals(e).first()
-                } catch {
-                    return logger.warn("unable to query data from indexedDB"),
-                    Promise.resolve(e)
-                }
-                const s = window.performance.now();
-                logger.debug(`search ${e} takes:${s - o}ms`);
-                const l = `${a && a.model ? "found" : "notFound"} data by search ${e} `;
-                if (logger.debug(l),
-                reporter$1.report("measurement", {
-                    type: "indexedDB",
-                    value: s - o,
-                    extra: l
-                }),
-                a && a.model) {
-                    const u = dataURItoBlob$1(a.model);
-                    return Promise.resolve(URL.createObjectURL(u))
-                } else
-                    return this.request({
-                        url: e,
-                        timeout: r,
-                        contentType: "blob",
-                        key: n
-                    }).then(async u=>{
-                        const c = await blobToDataURI$2(u.response);
-                        try {
-                            modelTable.models.add({
-                                name: e,
-                                model: c
-                            })
-                        } catch {
-                            logger.warn("unable to add data to indexedDB")
-                        }
-                        return Promise.resolve(URL.createObjectURL(u.response))
-                    }
-                    ).catch(u=>Promise.reject(u))
-            } else
-                return this.request({
-                    url: e,
-                    timeout: r,
-                    contentType: "blob",
-                    key: n
-                }).then(o=>{
-                    const a = o.response;
-                    return Promise.resolve(URL.createObjectURL(a))
-                }
-                ).catch(o=>Promise.reject(o));
-        else
-            return this.request({
-                url: e,
-                timeout: 5e3,
-                key: n
-            }).then(o=>o.getResponseHeader("content-type") === "application/json" ? Promise.resolve(JSON.parse(o.responseText)) : Promise.resolve(o.responseText)).catch(o=>{
-                Promise.reject(o)
-            }
-            )
-    }
-    request({url: e, timeout: t=15e3, contentType: r, key: n}) {
-        return new Promise((o,a)=>{
-            const s = window.performance.now()
-              , l = new XMLHttpRequest;
-            r && (l.responseType = r),
-            l.timeout = t,
-            l.addEventListener("readystatechange", ()=>{
-                if (l.readyState == 4)
-                    if (l.status == 200) {
-                        const u = window.performance.now();
-                        return logger.debug(`download ${e} takes:${u - s}ms`),
-                        reporter$1.report("measurement", {
-                            type: "http",
-                            value: u - s,
-                            extra: e
-                        }),
-                        this.emit("loadend", {
-                            message: `request ${e} load success`
-                        }),
-                        o(l)
-                    } else {
-                        const u = `Unable to load the request ${e}`;
-                        return this.emit("error", {
-                            message: u
-                        }),
-                        logger.error(u),
-                        a(u)
-                    }
-            }
-            ),
-            l.open("GET", e),
-            l.send()
-        }
-        )
-    }
-}
-
-const http2 = new Http2();
-export { http2 };
-
-// const http = new Http
-//   , isIndexedDbSupported = ()=>(window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB) !== void 0
-//   , blobToDataURI = async i=>new Promise((e,t)=>{
-//     const r = new FileReader;
-//     r.readAsDataURL(i),
-//     r.onload = function(n) {
-//         var o;
-//         e((o = n.target) == null ? void 0 : o.result)
-//     }
-//     ,
-//     r.onerror = function(n) {
-//         t(n)
-//     }
-// }
-// )
-//   , dataURItoBlob = i=>{
-//     let e;
-//     i.split(",")[0].indexOf("base64") >= 0 ? e = atob(i.split(",")[1]) : e = unescape(i.split(",")[1]);
-//     const t = i.split(",")[0].split(":")[1].split(";")[0]
-//       , r = new Uint8Array(e.length);
-//     for (let o = 0; o < e.length; o++)
-//         r[o] = e.charCodeAt(o);
-//     return new Blob([r],{
-//         type: t
-//     })
-// }
-//   , urlMap = new Map
-//   , urlTransformer = async(i,e=!1)=>typeof i != "string" ? (console.warn("url transformer error", i),
-// i) : i.startsWith("blob:") ? i : e ? http.get({
-//     url: i,
-//     useIndexedDb: !0,
-//     key: "url",
-//     isOutPutObjectURL: !1
-// }) : urlMap.has(i) ? urlMap.get(i) : http.get({
-//     url: i,
-//     useIndexedDb: !0,
-//     key: "url"
-// }).then(t=>(urlMap.set(i, t),
-// t));

+ 165 - 45
src/JoyStick.js

@@ -1,64 +1,184 @@
-export default class JoyStick {
-    constructor(e) {
-        this._zone = document.createElement("div")
-        this._joystick = null
-        this._room = e
-    }
-    init(e) {
-        const { interval=33, triggerDistance=25, style={left:0, bottom:0} } = e
+import Logger from "./Logger.js"
+import XJoystick from "./XJoystick.js"
+
+const logger = new Logger('Joystick')
 
-        const moveFunc = (u,c)=>{
+export default class JoyStick extends EventEmitter{
+    constructor(s) {
+        super();
+        this._zone = null;
+        this._joystick = null;
+        this._room = null;
+        this.useCanvas = !0;
+        this._xjoystick = null;
+        this.isHidden = !1;
+        this.inited = !1;
+        this._room = s
+    }
+    get zone() {
+        return this._zone
+    }
+    init(s) {
+        var it, nt;
+        if (this.useCanvas)
+            return this.initJoyStick(s);
+        this.destroy();
+        const c = {
+            position: "absolute",
+            width: "200px",
+            height: "200px",
+            left: "0px",
+            bottom: "0px",
+            zIndex: "999",
+            userSelect: "none",
+            webkitUserSelect: "none"
+        }
+          , {interval: _=33, triggerDistance: b=25, size: k=110, zoneClassName: j="xverse-joystick-zone"} = s || {};
+        typeof ((it = s == null ? void 0 : s.style) == null ? void 0 : it.left) == "number" && (s.style.left = s.style.left + "px"),
+        typeof ((nt = s == null ? void 0 : s.style) == null ? void 0 : nt.bottom) == "number" && (s.style.bottom = s.style.bottom + "px");
+        const $ = Object.assign(c, s == null ? void 0 : s.style)
+          , _e = (at,ot)=>{
+            let st = -Math.floor(at) + 90 + 360;
+            st >= 360 && (st -= 360),
             this._room.actionsHandler.joystick({
-                degree: Math.floor(u),
-                level: Math.floor(c / 5)
+                degree: st,
+                level: Math.floor(ot / 5)
             })
         }
-        const a = this._zone;
-
-        document.body.appendChild(a),
-        a.style.position = "absolute",
-        a.style.width = style.width || "200px",
-        a.style.height = style.height || "200px",
-        a.style.left = String(style.left || 0),
-        a.style.bottom = String(style.bottom || 0),
-        a.style.zIndex = "999",
-        a.style.userSelect = "none",
-        a.style.webkitUserSelect = "none",
+          , et = this._zone = document.createElement("div");
+        document.body.appendChild(et),
+        et.className = j,
+        Object.keys($).forEach(at=>{
+            const ot = $[at];
+            ot !== void 0 && (et.style[at] = ot)
+        }
+        ),
         this._joystick = nipplejs.create({
-            zone: a,
+            zone: et,
             mode: "static",
             position: {
                 left: "50%",
                 top: "50%"
             },
-            color: "white"
-        });
-
-        let s, l;
-        this._joystick.on("move", (u,c)=>{
-            s = c
-        })
+            color: "white",
+            restOpacity: .3,
+            size: k
+        }),
+        this.customizeStyle();
+        let tt, rt;
+        return this._joystick.on("move", (at,ot)=>{
+            tt = ot
+        }
+        ),
         this._joystick.on("start", ()=>{
-            l = window.setInterval(()=>{
-                s && s.distance > triggerDistance && moveFunc && moveFunc(s.angle.degree, s.distance)
+            rt = window.setInterval(()=>{
+                tt && tt.distance > b && _e && _e(tt.angle.degree, tt.distance)
             }
-            , interval)
-        })
+            , _)
+        }
+        ),
         this._joystick.on("end", ()=>{
-            l && window.clearInterval(l),
-            l = void 0
-        })
-
-        return this._joystick
+            rt && window.clearInterval(rt),
+            rt = void 0
+        }
+        ),
+        this._joystick
+    }
+    initJoyStick(s) {
+        var rt, it, nt, at, ot, st, lt, ut, ct;
+        if (this.inited)
+            return;
+        this.inited = !0,
+        logger.debug("init joystick", s);
+        let c;
+        const {interval: _=33, triggerDistance: b=25, puckSize: k=33} = s || {};
+        let {size: j=110} = s || {}
+          , $ = 70
+          , _e = 70;
+        typeof ((rt = s == null ? void 0 : s.style) == null ? void 0 : rt.width) == "string" && typeof ((it = s == null ? void 0 : s.style) == null ? void 0 : it.height) == "string" && ((nt = s == null ? void 0 : s.style) == null ? void 0 : nt.width) === ((at = s == null ? void 0 : s.style) == null ? void 0 : at.height) && (j = parseFloat((ot = s == null ? void 0 : s.style) == null ? void 0 : ot.width)),
+        typeof ((st = s == null ? void 0 : s.style) == null ? void 0 : st.left) == "string" && ($ = parseFloat((lt = s == null ? void 0 : s.style) == null ? void 0 : lt.left)),
+        typeof ((ut = s == null ? void 0 : s.style) == null ? void 0 : ut.bottom) == "string" && (_e = parseFloat((ct = s == null ? void 0 : s.style) == null ? void 0 : ct.bottom));
+        const et = {
+            thumbAreaSize: j,
+            puckSize: k,
+            leftPadding: $,
+            bottomPadding: _e
+        };
+        this._xjoystick = new XJoystick(et,this._room.sceneManager);
+        const tt = (ht,dt)=>{
+            if (this.isHidden)
+                return;
+            let ft = -Math.floor(ht) + 90 + 360;
+            ft >= 360 && (ft -= 360),
+            this._room.actionsHandler.joystick({
+                degree: Math.floor(ft),
+                level: Math.floor(dt / 5)
+            })
+        }
+        ;
+        this._xjoystick.onStart(()=>{
+            this._room.eventsController.rotationEvent.isResponseRotating = !1,
+            c = window.setInterval(()=>{
+                this._xjoystick && (this._xjoystick.distance > b ? (this._room.sceneManager.playerController.puckActive = !0,
+                tt && tt(this._xjoystick.degree, this._xjoystick.distance)) : this._room.sceneManager.playerController.puckActive = !1),
+                this.emit("joystickMove")
+            }
+            , _)
+        }
+        ),
+        this._xjoystick.onEnd(()=>{
+            this._room.eventsController.rotationEvent.isResponseRotating = !0,
+            c && window.clearInterval(c),
+            c = void 0
+        }
+        )
+    }
+    destroy() {
+        if (!!this._joystick) {
+            this._joystick.destroy();
+            try {
+                this._zone && document.body.removeChild(this._zone)
+            } catch {}
+        }
+    }
+    customizeStyle() {
+        var k, j;
+        const s = this._zone;
+        if (!s)
+            return;
+        const c = s.querySelector(".front")
+          , _ = s.querySelector(".back")
+          , b = 30;
+        c.style.width = b + "px",
+        c.style.height = b + "px",
+        c.style.marginLeft = b / -2 + "px",
+        c.style.marginTop = b / -2 + "px",
+        _.style.boxSizing = "border-box",
+        _.style.backgroundColor = "black",
+        _.style.backgroundClip = "padding-box",
+        _.style.border = "2px solid white",
+        (k = this._joystick) == null || k.on("start", ()=>{
+            _.style.border = "2px solid #FFEA95",
+            _.style.boxShadow = "inset 0px 0px 8px rgba(255, 255, 255, 0.25)",
+            c.style.opacity = "1"
+        }
+        ),
+        (j = this._joystick) == null || j.on("end", ()=>{
+            _.style.border = "2px solid white",
+            _.style.boxShadow = "none"
+        }
+        )
     }
     show() {
-        if (!this._joystick)
-            throw new Error("joystick is not created");
-        this._zone.style.display = "block"
+        var s;
+        this._zone && (this._zone.style.display = "block"),
+        (s = this._xjoystick) == null || s.show(),
+        this.isHidden = !1
     }
     hide() {
-        if (!this._joystick)
-            throw new Error("joystick is not created");
-        this._zone.style.display = "none"
+        var s;
+        this._zone && (this._zone.style.display = "none"),
+        (s = this._xjoystick) == null || s.hide(),
+        this.isHidden = !0
     }
 }

+ 23 - 75
src/Logger.js

@@ -1,84 +1,32 @@
-import Codes from "./enum/Codes.js"
-import {reporter} from "./Reporter.js"
-import util from "./util.js"
+const DEFAULT_LOGGER = {
+    debug: console.log,
+    info: console.log,
+    warn: console.warn,
+    error: console.error,
+    infoAndReportMeasurement: (...d)=>{}
+}
 
 export default class Logger{
-    constructor(e) {
-        this.level = 3
-        this.module = e
+    // static setLogger(d) {
+    //     Logger.instance = DEFAULT_LOGGER
+    // }
+    constructor(d) {
+        this.module = d
+        Logger.instance = DEFAULT_LOGGER;
     }
-    static setLevel(e) {
-        this.level = e
+    debug(...d) {
+        return Logger.instance.debug(...d)
     }
-    setLevel(e) {
-        this.level = e
+    info(...d) {
+        return Logger.instance.info(...d)
     }
-    atleast(e) {
-        return e >= this.level && e >= this.level
+    warn(...d) {
+        return Logger.instance.warn(...d)
     }
-    print(e, t, ...r) {
-        if (this.atleast(t)) {
-            const n = e == "debug" ? "info" : e
-              , o = this.prefix(e);
-            console[n].call(null, o, ...r)
-        }
-        if (e !== "debug" && e !== "info") {
-            const n = r.map(o=>{
-                if (o instanceof Object)
-                    try {
-                        return JSON.stringify(o)
-                    } catch {
-                        return o
-                    }
-                else
-                    return o
-            }
-            ).join(",");
-            reporter.report("log", {
-                message: n,
-                level: e,
-                module: this.module
-            })
-        }
+    error(...d) {
+        return Logger.instance.error(...d)
     }
-    debug(...e) {
-        return this.print("debug", 1, ...e)
-    }
-    info(...e) {
-        return this.print("info", 2, ...e)
-    }
-    infoAndReportLog(e, ...t) {
-        const {reportOptions: r} = e;
-        delete e.reportOptions,
-        reporter.report("log", e, r),
-        t.length || (t = [e.message]),
-        this.debug(...t)
-    }
-    infoAndReportMeasurement(e, ...t) {
-        var n;
-        const {reportOptions: r} = e;
-        if (e.startTime) {
-            const o = Date.now();
-            e.value === void 0 && (e.endTime = o),
-            e.value === void 0 && (e.value = o - e.startTime)
-        }
-        if (e.error ? e.code = ((n = e.error) == null ? void 0 : n.code) || Codes.Internal : e.code = Codes.Success,
-        reporter.report("measurement", e, r),
-        t.length || (t = [e]),
-        e.level === 4 || e.error) {
-            this.error(...t);
-            return
-        }
-        this.warn(...t)
-    }
-    warn(...e) {
-        return this.print("warn", 3, ...e)
-    }
-    error(...e) {
-        return this.print("error", 4, ...e)
-    }
-    // console前缀
-    prefix(e) {
-        return `[${this.module}] [${util.getFormattedDate(new Date)}]`
+    infoAndReportMeasurement(...d) {
+        return Logger.instance.infoAndReportMeasurement(...d)
     }
 };

+ 230 - 145
src/ModelManager.js

@@ -1,199 +1,215 @@
-import {http1} from "./Http1.js"
-import util from "./util.js"
+import {http} from "./Http.js"
+import Person  from "./enum/Person.js"
 import Logger from "./Logger.js"
 import ParamError from "./error/ParamError.js"
+import InitConfigTimeoutError from "./error/InitConfigTimeoutError.js"
+import ComponentItemType from "./enum/ComponentItemType.js"
 
 const logger = new Logger('model-manager')
+const objectParseFloat = d=>{
+    const o = {};
+    return d && Object.keys(d).forEach(s=>{
+        o[s] = parseFloat(d[s])
+    }
+    ),
+    o
+}
+
 export default class ModelManager{
-    constructor(e, t) {
-        this.avatarModelList = []
-        this.skinList = []
+    constructor(o, s) {
+        this.avatarModelList = [];
+        this.skinList = [];
         this.applicationConfig = null;
-        this.config = null
-        this.appId = e,
-        this.releaseId = t
-    }
-    static getInstance(e, t) {
-    //getInstance(e, t) {
-        return this.instance || (this.instance = new ModelManager(e,t)),
-        this.instance
-    }
-    static findModels(e, t, r) {
-    //findModels(e, t, r) {
-        return e.filter(o=>o.typeName === t && o.className === r)
-    }
-    static findModel(e, t, r) {
-    //findModel(e, t, r) {
-        const n = e.filter(o=>o.typeName === t && o.className === r)[0];
-        return n || null
-    }
-    async findSkinConfig(skinId) {
-        let t = null;
-        if (t = (this.skinList = await this.getSkinsList()).find(n=>n.id === skinId),
-        t)
-            return t;
+        this.config = null;
+        this.appId = o,
+        this.releaseId = s
+    }
+    static getInstance(o, s) {
+        return ModelManager.instance || (ModelManager.instance = new ModelManager(o,s)),
+        ModelManager.instance
+    }
+    static findModels(o, s) {
+        return o.filter(_=>_.type === s)
+    }
+    static findModel(o, s) {
+        const c = o.filter(_=>_.type === s)[0];
+        return c || null
+    }
+    async findSkinConfig(o) {
+        let s = null;
+        if (s = (this.skinList = await this.getSkinsList()).find(_=>_.id === o),
+        s)
+            return s;
         {
-            const n = `skin is invalid: skinId: ${skinId}`;
-            return Promise.reject(new ParamError(n))
+            const _ = `skin is invalid: skinId: ${o}`;
+            return Promise.reject(new ParamError(_))
         }
     }
-    async findRoute(skinId, pathName) {
-        const route = (await this.findSkinConfig(skinId)).routeList.find(o=>o.pathName === pathName);
-        if (!route) {
-            const errMessage = `find path failed: skinId: ${skinId}, pathName: ${pathName}`;
-            return Promise.reject(new ParamError(errMessage))
+    async findPath(o, s) {
+        console.trace("findPath", s);
+        const _ = (await this.findSkinConfig(o)).pathList.find(b=>b.id === s);
+        if (!_) {
+            const b = `find path failed: skinId: ${o}, pathName: ${s}`;
+            return Promise.reject(new ParamError(b))
         }
-        return logger.debug("find route success", route),
-        route
-    }
-    async findAssetList(e) {
-        const r = (await this.findSkinConfig(e)).assetList;
-        if (!r) {
-            const n = `find path failed: skinId: ${e}`;
-            return Promise.reject(new ParamError(n))
+        return logger.debug("find route success", _),
+        _
+    }
+    async findAssetList(o) {
+        const c = (await this.findSkinConfig(o)).assetList;
+        if (!c) {
+            const _ = `find path failed: skinId: ${o}`;
+            return Promise.reject(new ParamError(_))
         }
-        return logger.debug("find route success", r),
-        r
-    }
-    async findAsset(e, t, r="id") {
-        const n = await this.findSkinConfig(e);
-        if (Array.isArray(t))
-            return t.map(a=>n.models.find(s=>s[r] === a)).filter(Boolean);
-        const o = n.models.find(a=>a[r] === t);
-        if (!o) {
-            const a = `find asset failed: skinId: ${e}, keyValue: ${t}`;
-            return Promise.reject(new ParamError(a))
+        return logger.debug("find route success", c),
+        c
+    }
+    async findAsset(o, s, c="id") {
+        const _ = await this.findSkinConfig(o);
+        if (Array.isArray(s))
+            return s.map(k=>_.assetList.find(j=>j[c] === k)).filter(Boolean);
+        const b = _.assetList.find(k=>k[c] === s);
+        if (!b) {
+            const k = `find asset failed: skinId: ${o}, keyValue: ${s}`;
+            return Promise.reject(new ParamError(k))
         }
-        return logger.debug("find asset success", o),
-        o
-    }
-    async findPoint(e, t) {
-        const n = (await this.findSkinConfig(e)).pointList.find(o=>o.id === t);
-        if (!n) {
-            const o = `find point failed: skinId: ${e}, id: ${t}`;
-            return Promise.reject(new ParamError(o))
+        return logger.debug("find asset success", b),
+        b
+    }
+    async findCameraAndPlayer(o, s) {
+        const c = await this.findPath(o, s)
+          , _ = getRandomItem(c.birthPointList);
+        return _ || Promise.reject(new ParamError("find camera and player failed"))
+    }
+    async findPoint(o, s) {
+        const _ = (await this.findSkinConfig(o)).pointList.find(b=>b.id === s);
+        if (!_) {
+            const b = `find point failed: skinId: ${o}, id: ${s}`;
+            return Promise.reject(new ParamError(b))
         }
-        return logger.debug("find point success", n),
-        n
+        return logger.debug("find point success", _),
+        _
     }
     async requestConfig() {
         if (this.config)
             return this.config;
-        // let e = `https://static.xverse.cn/console/config/${this.appId}/config.json`;
-        // this.releaseId && (e = `https://static.xverse.cn/console/config/${this.appId}/${this.releaseId}/config.json`);
-        // const t = Xverse.USE_TME_CDN ? "https://static.xverse.cn/tmeland/config/tme_config.json" : e;
-        const t = './assets/config.json'
+        //let o = `assets/${this.appId}/config.json`;
+        let o = `assets/config.json`;
+        this.releaseId && (o = `https://static.xverse.cn/console/config/${this.appId}/${this.releaseId}/config.json`),
+        ModelManager.configCdnHost && (o = o.replace(/(https?:\/\/)(.*?)(\/.*)/g, "$1" + ModelManager.configCdnHost + "$3"));
         try {
-            const r = await http1.get({
-                url: `${t}?t=${Date.now()}`,
+            const s = await http.get({
+                url: o,
                 key: "config",
                 timeout: 6e3,
                 retry: 2
-            });
-
-            const {config: n, preload: o} = r.data.data || {};
-            if (!n)
-                throw new Error("config data parse error" + r.data);
+            })
+              , {config: c, preload: _} = s.data.data || {};
+            if (!c)
+                throw new Error("config data parse error" + s.data);
             return this.config = {
-                config: n,
-                preload: o
+                config: c,
+                preload: _
             },
             logger.debug("get config success", this.config),
             this.config
-        } catch (r) {
-            return Promise.reject(r)
+        } catch (s) {
+            return Promise.reject(s)
         }
     }
     async getApplicationConfig() {
         if (this.applicationConfig)
             return this.applicationConfig;
         try {
-            const e = await this.requestConfig();
-            return this.applicationConfig = e.config,
+            const o = await this.requestConfig();
+            return this.applicationConfig = o.config,
             this.applicationConfig
-        } catch (e) {
-            return Promise.reject(e)
+        } catch (o) {
+            return Promise.reject(o)
         }
     }
     async getAvatarModelList() {
         if (this.avatarModelList.length)
             return this.avatarModelList;
         try {
-            const {avatars: e} = await this.getApplicationConfig();
-            return this.avatarModelList = e.map(t=>({
-                name: t.name,
-                id: t.id,
-                modelUrl: t.url,
-                gender: t.gender,
-                components: t.components
-            })),
+            const {avatarList: o, avatars: s} = await this.getApplicationConfig();
+            return o && o.length == 0 ? s && s.length > 0 && (this.avatarModelList = this.paraseOldAvatars(s)) : o && o.length > 0 && (this.avatarModelList = o),
             this.avatarModelList
-        } catch (e) {
-            return logger.error(e),
-            []
+        } catch (o) {
+            return logger.error(o),
+            Promise.reject(new InitConfigTimeoutError(o || "getAvatarModelList error"))
+        }
+    }
+    async getAvatarModel(o) {
+        try {
+            let s;
+            const c = await this.getAvatarModelList();
+            return s = c.find(_=>_.id === o),
+            s || (s = c.find(_=>_.name === o)),
+            s
+        } catch (s) {
+            return logger.error(s),
+            Promise.reject(new InitConfigTimeoutError(s || "getAvatarModelList error"))
         }
     }
     async getSkinsList() {
         if (this.skinList.length)
             return this.skinList;
         try {
-            const {skins: e} = await this.getApplicationConfig();
-            return this.skinList = e.map(t=>{
-                var r;
-                return {
-                    name: t.name,
-                    dataVersion: t.id + t.versionId,
-                    id: t.id,
-                    fov: parseInt(t.fov || 90),
-                    models: t.assetList.map(n=>{
-                        const {assetId: o, url: a, thumbnailUrl: s, typeName: l, className: u} = n;
-                        return {
-                            id: o,
-                            modelUrl: a,
-                            name: n.name,
-                            thumbnailUrl: s,
-                            typeName: l,
-                            className: u === "\u4F4E\u6A21" ? "\u7C97\u6A21" : u    //低模    粗模
-                        }
-                    }
-                    ),
-                    routeList: (r = t.routeList) == null ? void 0 : r.map(n=>{
-                        const {areaName: o, attitude: a, id: s, pathName: l, step: u, birthPointList: c} = n;
-                        return {
-                            areaName: o,
-                            attitude: a,
-                            id: s,
-                            pathName: l,
-                            step: u,
-                            birthPointList: c.map(h=>({
-                                camera: h.camera && {
-                                    position: util.objectParseFloat(h.camera.position),
-                                    angle: util.objectParseFloat(h.camera.rotation)
-                                },
-                                player: h.player && {
-                                    position: util.objectParseFloat(h.player.position),
-                                    angle: util.objectParseFloat(h.player.rotation)
-                                }
-                            }))
+            const {skins: o} = await this.getApplicationConfig();
+            return this.skinList = o.map(s=>{
+                const c = parseInt(s.attr.fov || 90)
+                  , _ = s.attr.resolution
+                  , b = s.pathList.map(j=>{
+                    const $ = j.birthPointList.map(et=>({
+                        camera: et.camera && {
+                            position: objectParseFloat(et.camera.position),
+                            angle: objectParseFloat(et.camera.rotation)
+                        },
+                        player: et.player && {
+                            position: objectParseFloat(et.player.position),
+                            angle: objectParseFloat(et.player.rotation)
                         }
+                    }))
+                      , _e = j.personType === "ThirdPerson" ? Person.Third : Person.First;
+                    return {
+                        ...j,
+                        person: _e,
+                        birthPointList: $
                     }
-                    ),
-                    pointList: t.pointList.map(n=>le(oe({}, n), {
-                        position: util.objectParseFloat(n.position),
-                        rotation: util.objectParseFloat(n.rotation)
-                    })),
-                    versionId: t.versionId,
-                    isEnable: t.isEnable,
-                    assetList: t.assetList,
-                    visibleRules: t.visibleRules,
-                    animationList: t.animationList
+                }
+                )
+                  , k = s.pointList.map(j=>({
+                    ...j,
+                    position: objectParseFloat(j.point.position),
+                    rotation: objectParseFloat(j.point.rotation)
+                }));
+                return {
+                    name: s.name,
+                    dataVersion: s.id + s.versionId,
+                    id: s.id,
+                    tag: s.tag,
+                    fov: c,
+                    resolution: _,
+                    attr: {
+                        fov: c,
+                        resolution: _
+                    },
+                    areaList: s.areaList,
+                    pathList: b,
+                    pointList: k,
+                    versionId: s.id === "10099" && s.versionId === "00034" ? "00023" : s.versionId,
+                    isEnable: s.isEnable,
+                    assetList: s.assetList,
+                    visibleRules: s.visibleRules,
+                    animationList: s.animationList
                 }
             }
             ),
             this.skinList
-        } catch (e) {
-            return logger.error(e),
-            []
+        } catch (o) {
+            return logger.error(o),
+            Promise.reject(new InitConfigTimeoutError(o || "getSkinsList error"))
         }
     }
     async getBreathPointTextrueList() {
@@ -201,7 +217,76 @@ export default class ModelManager{
             url: TEXTURE_URL
         }]
     }
+    async findEffectList(o) {
+        const c = (await this.findSkinConfig(o)).assetList.filter(_=>_.type === AssetTypeName.Effects);
+        if (!c) {
+            const _ = `find effect failed: skinId: ${o}`;
+            return Promise.reject(new ParamError(_))
+        }
+        return logger.debug("find asset success", c),
+        c
+    }
+    paraseOldAvatars(o) {
+        const s = [];
+        return o.forEach(c=>{
+            const _ = [];
+            c.components.forEach(et=>{
+                const tt = {
+                    type: et.type.toLocaleUpperCase(),
+                    unitList: et.units
+                };
+                _.push(tt)
+            }
+            );
+            const b = [];
+            c.animations.forEach(et=>{
+                const tt = {
+                    id: c.id + et.name,
+                    isDefault: et.name === "Idle",
+                    name: et.name,
+                    url: et.url
+                };
+                b.push(tt)
+            }
+            );
+            const k = {
+                type: ComponentItemType.ANIMATION,
+                unitList: b
+            };
+            _.push(k);
+            const j = {
+                type: ComponentItemType.BODY,
+                unitList: [{
+                    id: c.id,
+                    isDefault: !0,
+                    name: c.name,
+                    url: c.url
+                }]
+            };
+            _.push(j);
+            const $ = {
+                type: ComponentItemType.SKELETON,
+                unitList: [{
+                    id: c.id,
+                    isDefault: !0,
+                    name: c.name,
+                    url: c.url
+                }]
+            };
+            _.push($);
+            const _e = {
+                name: c.name,
+                id: c.id,
+                componentList: _
+            };
+            s.push(_e)
+        }
+        ),
+        s
+    }
 };
 
 // const modelManager = new ModelManager();
 // export { modelManager };
+ModelManager.configCdnHost = null;
+ModelManager.instance = null;

+ 157 - 194
src/NetworkController.js

@@ -7,128 +7,136 @@ import InternalError from "./error/InternalError.js"
 import util from "./util.js"
 import Actions from "./enum/Actions.js"
 import Logger from "./Logger.js"
+import {tracker} from "./Tracker.js"
 
 const logger = new Logger('NetworkController')
-
-var workerSourceCode = `onmessage = function (event) {
-    const data = event.data
-    if (!data) return
-  
-    if (data.type === 'start') {
-      const startTime = Date.now()
-      const request = new XMLHttpRequest()
-      request.open('GET', data.url)
-      try {
-        request.send()
-      } catch (error) {
-        console.error(error)
-      }
-      request.addEventListener('readystatechange', () => {
-        if (request.readyState == 4) {
-          if (request.status == 200) {
-            postMessage(Date.now() - startTime)
-          }
+let worker = null;
+function checkNetworkQuality(d) {
+    if (!d)
+        return;
+    const o = Date.now();
+    if (pingOthers("https://www.baidu.com", function(s, c) {
+        logger.infoAndReportMeasurement({
+            metric: "baiduRtt",
+            group: "http",
+            value: c,
+            startTime: o
+        })
+    }),
+    !worker) {
+        const s = new Blob([workerSourceCode],{
+            type: "application/javascript"
+        });
+        worker = new Worker(URL.createObjectURL(s)),
+        worker.onmessage = function(c) {
+            logger.infoAndReportMeasurement({
+                metric: "workerRtt",
+                group: "http",
+                startTime: o,
+                value: c.data
+            })
         }
-      })
     }
-  }
-  `;
+}
+function pingOthers(d, o) {
+    let s = !1;
+    const c = new Image;
+    c.onload = b,
+    c.onerror = k;
+    const _ = Date.now();
+    function b($) {
+        s = !0,
+        j()
+    }
+    function k($) {}
+    function j() {
+        const $ = Date.now() - _;
+        if (typeof o == "function")
+            return s ? o(null, $) : (console.error("error loading resource"),
+            o("error", $))
+    }
+    c.src = d + "/favicon.ico?" + +new Date
+}
   
 export default class NetworkController extends EventEmitter {
-    constructor(e) {
+    constructor(s) {
         super();
-        this.socket = null
-        this.rtcp = null
-        this.stream = null
-        this._state = 'connecting'
-        this._networkMonitor = null
-        this.blockedActions = []
-        this.reconnectCount = 0
-        this.room = e,
-        this.socket = new Socket(this);
-        this.rtcp = new Rtcp(this);
-        this.stream = new Stream;
-        this._networkMonitor = new NetworkMonitor(()=>{
-            logger.info("network changed, online:", this._networkMonitor.isOnline),
-            this._state === "disconnected" && this._networkMonitor.isOnline && (logger.info("network back to online, try to reconnect"),
-            this.reconnect())
-        });
-
-        this.checkNetworkQuality(this.room.currentNetworkOptions.wsServerUrl);
-        this._networkMonitor.start();
-
-        new VisibilityChangeHandler().subscribe(r=>{
-                var n, o;
-                r ? ((o = this.room.stats) == null || o.disable(),
-                logger.infoAndReportMeasurement({
-                    type: "pageHide"
-                })) : ((n = this.room.stats) == null || n.enable(),
-                logger.infoAndReportMeasurement({
-                    type: "pageShow",
-                    extraData: {
-                        state: this._state
-                    }
-                }),
-                this._state === "disconnected" && this.reconnect())
-            }
-        )
-    }
-
-    startGame(){
-        return new Promise((e,t)=>{
+        this.socket = null;
+        this.rtcp = null;
+        this._state = 'connecting';
+        this._networkMonitor = null;
+        this.reconnectCount = 0;
+        this.startGame = ()=>new Promise((s,c)=>{
             if (!this.rtcp.connected)
-                return t(new InternalError("Game cannot load. Please refresh"));
+                return c(new InternalError("Game cannot load. Please refresh"));
             if (!this.rtcp.inputReady)
-                return t(new InternalError("Game is not ready yet. Please wait"));
-            this.socket.on("gameRoomAvailable", r=>{
-               
+                return c(new InternalError("Game is not ready yet. Please wait"));
+            this.socket.on("gameRoomAvailable", _=>{
                 this.setState("connected"),
-                e(r),
+                s(_),
                 this.rtcp.heartbeat.start()
             }
             ),
-            this.socket.on("socketClosed", r=>{
-                t(r)
+            this.socket.on("socketClosed", _=>{
+                c(_)
             }
             ),
             this.socket.startGame()
-        })
-    }
-
-    addBlockedActions(e) {
-        this.blockedActions.push(...e)
-    }
-    removeBlockedActions(e) {
-        if (!e) {
-            this.blockedActions = [];
-            return
         }
-        const t = this.blockedActions.indexOf(e);
-        this.blockedActions.splice(t, 1)
+        )
+        this.room = s,
+        this.socket = new Socket(this),
+        this.rtcp = new Rtcp(this),
+        this._networkMonitor = new NetworkMonitor(()=>{
+            logger.warn("network changed, online:", this._networkMonitor.isOnline),
+            this._state === "disconnected" && this._networkMonitor.isOnline && (logger.warn("network back to online, try to reconnect"),
+            this.reconnect())
+        }
+        ),
+        checkNetworkQuality(this.room.currentNetworkOptions.wsServerUrl),
+        this._networkMonitor.start(),
+        new VisibilityChangeHandler().subscribe(_=>{
+            var b, k;
+            _ ? ((k = this.room.stats) == null || k.disable(),
+            this.room.pageHideHandler(),
+            logger.infoAndReportMeasurement({
+                metric: "pageHide",
+                startTime: Date.now()
+            })) : ((b = this.room.stats) == null || b.enable(),
+            this.room.pageShowHandler(),
+            logger.infoAndReportMeasurement({
+                metric: "pageShow",
+                startTime: Date.now(),
+                extra: {
+                    state: this._state
+                }
+            }),
+            this._state === "disconnected" && (logger.warn("page show, try to reconnect"),
+            this.reconnect()))
+        }
+        )
     }
-    setState(e) {
-        this._state !== e && (logger.info("Set network state to ", e),
-        this._state = e)
+    setState(s) {
+        this._state !== s && (this._state === "closed" && !NetworkController.ALLOW_RECONNECT_AFTER_QUIT || (logger.info("Set network state to ", s),
+        this._state = s))
     }
-    async connectAndStart(e) {
-        return this.connect(e).then(this.startGame)
+    async connectAndStart(s) {
+        return this.connect(s).then(()=>this.room.joined ? this.startGame() : Promise.resolve({}))
     }
-    async connect(e=!1) {
-     
-        this.room.updateCurrentNetworkOptions({
-            reconnect: e
-        });
-        return new Promise((t,r)=>{
-      
+    async connect(s=!1) {
+        return this.room.updateCurrentNetworkOptions({
+            reconnect: s
+        }),
+        new Promise((c,_)=>{
             this.rtcp.on("rtcConnected", ()=>{
                 this.setState("connected"),
-                t()
+                c()
             }
             ),
-            this.rtcp.on("rtcDisconnected", ()=>{
+            this.rtcp.on("rtcDisconnected", b=>{
                 logger.info("rtc disconnected"),
                 this._state === "connecting" ? (this.setState("disconnected"),
-                r(new InternalError("rtc connect failed"))) : (this.setState("disconnected"),
+                _(b || new InternalError("rtc connect failed"))) : (this.setState("disconnected"),
                 logger.info("rtc disconnected, start to reconnect"),
                 this.reconnect())
             }
@@ -138,10 +146,10 @@ export default class NetworkController extends EventEmitter {
                 this.setState("closed")
             }
             ),
-            this.socket.on("socketClosed", n=>{
+            this.socket.on("socketClosed", b=>{
                 this._state === "connecting" && (this.setState("disconnected"),
-                r(n)),
-                r(n)
+                _(b)),
+                _(b)
             }
             ),
             this.socket.start()
@@ -149,47 +157,47 @@ export default class NetworkController extends EventEmitter {
         )
     }
     reconnect() {
-        // webrtc的IceConnectionState为disconnected时,前端连接断开并尝试重连
-        if (this.room.viewMode === "observer")
-            return;
-        const e = Date.now();
-        if (this.reconnectCount++,
-        this.reconnectCount > MAX_RECONNECT_COUNT) {
-            logger.error("reconnect failed, reached max reconnect count", MAX_RECONNECT_COUNT),
-            this.reconnectCount = 0,
-            this.emit("stateChanged", {
-                state: "disconnected"
-            });
-            return
-        }
-        return logger.info("start reconnect, count:", this.reconnectCount),
+        const s = Date.now();
+        return logger.warn("start reconnect, count:", this.reconnectCount),
         this._reconnect().then(()=>{
             logger.infoAndReportMeasurement({
-                type: "reconnect"
+                startTime: s,
+                metric: "reconnect"
             })
         }
-        ).catch(t=>{
+        ).catch(c=>{
+            if (c.code === Codes.ConnectingAlready)
+                return;
             if (logger.infoAndReportMeasurement({
-                type: "reconnect",
-                error: t
+                startTime: s,
+                metric: "reconnect",
+                error: c
             }),
-            t.code === Codes.RepeatLogin) {
+            (c == null ? void 0 : c.code) === Codes.RepeatLogin) {
                 this.room.handleRepetLogin();
                 return
             }
-            const r = 1e3;
-            logger.info("reconnect failed, wait " + r + " ms for next reconnect"),
+            if (this.reconnectCount++,
+            this.reconnectCount > MAX_RECONNECT_COUNT) {
+                logger.error("reconnect failed, reached max reconnect count", MAX_RECONNECT_COUNT),
+                this.reconnectCount = 0,
+                this.setState("disconnected"),
+                this.emit("stateChanged", {
+                    state: "disconnected"
+                });
+                return
+            }
+            const _ = 1e3;
+            logger.warn("reconnect failed, wait " + _ + " ms for next reconnect"),
             setTimeout(()=>{
                 this.reconnect()
             }
-            , r)
+            , _)
         }
         )
     }
     _reconnect() {
-        return this._state === "closed" ? (logger.warn("connection closed already"),
-        Promise.reject()) : this._state === "connecting" ? (logger.warn("connection is already in connecting state"),
-        Promise.reject()) : this._state !== "disconnected" ? Promise.reject() : (this.prepareReconnect(),
+        return this._state === "closed" ? Promise.reject(new InternalError("connection closed already")) : this._state === "connecting" ? Promise.reject(new ConnectingAlreadyError("connection is already in connecting state")) : this._state !== "disconnected" ? Promise.reject(new InternalError("_state is state: " + this._state)) : (this.prepareReconnect(),
         this._state = "connecting",
         this.emit("stateChanged", {
             state: "reconnecting",
@@ -199,19 +207,22 @@ export default class NetworkController extends EventEmitter {
         this.socket.off("socketClosed"),
         this.rtcp.off("rtcDisconnected"),
         this.rtcp.off("rtcConnected"),
-        this.connectAndStart(!0).then(({session_id: e})=>{
-            this.room.updateCurrentNetworkOptions({
-                sessionId: e
+        this.connectAndStart(!0).then(({session_id: s})=>{
+            !s || (this.room.updateCurrentNetworkOptions({
+                sessionId: s
             }),
             reporter.updateBody({
-                serverSession: e
+                serverSession: s
+            }),
+            tracker.updateHeader({
+                serverSession: s
             }),
-            logger.info("reconnect success"),
+            logger.warn("reconnect success"),
             this.setState("connected"),
             this.reconnectCount = 0,
             this.emit("stateChanged", {
                 state: "reconnected"
-            })
+            }))
         }
         ))
     }
@@ -221,80 +232,32 @@ export default class NetworkController extends EventEmitter {
         this.prepareReconnectOptions()
     }
     prepareReconnectOptions() {
-        const {camera: e, player: t} = this.room.currentClickingState || {};
-        e && t && this.room.updateCurrentNetworkOptions({
-            camera: e,
-            player: t
+        const {camera: s, player: c} = this.room.currentClickingState || {};
+        s && c && this.room.updateCurrentNetworkOptions({
+            camera: s,
+            player: c
         })
     }
-    sendRtcData(e) {
-        if (this.blockedActions.includes(e.action_type)) {
-            logger.info(`action: ${Actions[e.action_type]} was blocked`);
-            return
-        }
-        this.rtcp.sendData(e)
+    sendRtcData(s) {
+        this.rtcp.sendData(s)
     }
-    sendSocketData(e) {
-        logger.debug("ws send ->", e),
-        this.socket.send(e)
+    sendSocketData(s) {
+        logger.debug("ws send ->", s),
+        this.socket.send(s)
     }
     quit() {
-        const e = util.uuid()
-          , t = {
+        const s = uuid$1()
+          , c = {
             action_type: Actions.Exit,
-            trace_id: e,
+            trace_id: s,
             exit_action: {},
             user_id: this.room.options.userId,
-            packet_id: e
+            packet_id: s
         };
         this.setState("closed"),
         this.socket.quit(),
-        this.sendRtcData(t)
+        this.sendRtcData(c)
     }
+}
 
-    checkNetworkQuality(i) {
-        let worker = null
-        if (!i)
-            return;
-        const e = Date.now();
-        if (this.pingOthers("https://www.baidu.com", function(t, r) {
-            logger.infoAndReportMeasurement({
-                type: "baiduRtt",
-                group: "http",
-                value: r
-            })
-        }),
-        !worker) {
-            const t = new Blob([workerSourceCode],{
-                type: "application/javascript"
-            });
-            worker = new Worker(URL.createObjectURL(t)),
-            worker.onmessage = function(r) {
-                logger.infoAndReportMeasurement({
-                    type: "workerRtt",
-                    group: "http",
-                    value: r.data
-                })
-            }
-        }
-    }
-    pingOthers(i, e) {
-        let t = !1;
-        const r = new Image;
-        r.onload = o,
-        r.onerror = a;
-        const n = Date.now();
-        function o(l) {
-            t = !0,
-            s()
-        }
-        function a(l) {}
-        function s() {
-            const l = Date.now() - n;
-            if (typeof e == "function")
-                return t ? e(null, l) : (console.error("error loading resource"),
-                e("error", l))
-        }
-        r.src = i + "/favicon.ico?" + +new Date
-    }
-}
+NetworkController.ALLOW_RECONNECT_AFTER_QUIT = !0;

+ 5 - 4
src/NetworkMonitor.js

@@ -1,10 +1,11 @@
 export default class NetworkMonitor {
-    constructor(e) {
-        this._listener = e
+    constructor(o) {
+        this._listener = null;
+        this._listener = o
     }
     get isOnline() {
-        const e = window.navigator;
-        return typeof e.onLine == "boolean" ? e.onLine : !0
+        const o = window.navigator;
+        return typeof o.onLine == "boolean" ? o.onLine : !0
     }
     start() {
         window.addEventListener("online", this._listener),

+ 75 - 52
src/Panorama.js

@@ -3,89 +3,112 @@ import {eventsManager} from "./EventsManager.js"
 import util from "./util.js"
 import Logger from "./Logger.js"
 
+const isWebAssemblySupported = ()=>{
+    try {
+        if (typeof WebAssembly == "object" && typeof WebAssembly.instantiate == "function") {
+            const d = new WebAssembly.Module(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0));
+            if (d instanceof WebAssembly.Module)
+                return new WebAssembly.Instance(d)instanceof WebAssembly.Instance
+        }
+    } catch {}
+    return console.log("wasm is not supported"),
+    !1
+}
+;
 const logger = new Logger('panorama')
 export default class Panorama {
-    constructor(e) {
-        E(this, "_actived", !1);
-        E(this, "handleReceivePanorama", async(e,t)=>{
-            logger.warn("handle panorama", e.uuid, e.pos, e.finished);
-            const r = {
-                data: e.data,
+    constructor(o) {
+        this._actived = !1;
+        this.isLoading = !1;
+        this.handleReceivePanorama = async o=>{
+            const s = o.camera;
+            logger.warn("handle panorama", s);
+            const c = {
+                data: o.data,
                 pose: {
-                    position: e.pos
+                    position: s.position,
+                    rotation: s == null ? void 0 : s.angle
                 }
             }
-              , n = this.room.sceneManager;
+              , _ = this.room.sceneManager;
             if (this.room.networkController.rtcp.workers.changePanoMode(!0),
-            await n.materialComponent.changePanoImg(0, r),
-            !!e.finished)
-                if (await n.changePanoShaderForLowModel(0),
+            await _.materialComponent.changePanoImg(0, c),
+            !!o.finished)
+                if (await _.changePanoShaderForLowModel(0),
                 this.room.isPano = !0,
                 this._actived = !0,
-                t)
+                s)
                     this.room.sceneManager.cameraComponent.changeToFirstPersonView({
-                        position: t.position,
-                        rotation: t.angle
+                        position: s.position,
+                        rotation: s.angle
                     });
                 else {
-                    const {skinId: o, pathName: a} = this.room.currentState;
-                    if (!o || !a)
+                    const {skinId: b, pathId: k} = this.room.currentState;
+                    if (!b || !k)
                         return;
-                    const s = await this.room.modelManager.findRoute(o, a)
-                      , {camera: l} = util.getRandomItem(s.birthPointList) || {};
-                    l && this.room.sceneManager.cameraComponent.changeToFirstPersonView(le(oe({}, l), {
-                        rotation: l.angle
-                    }))
+                    const j = await this.room.modelManager.findPath(b, k)
+                      , {camera: $} = getRandomItem(j.birthPointList) || {};
+                    $ && this.room.sceneManager.cameraComponent.changeToFirstPersonView({
+                        ...$,
+                        rotation: $.angle
+                    })
                 }
-        }
-        );
-        this.room = e
+        };
+        this.room = o
     }
     get actived() {
         return this._actived
     }
-    bindListener(e) {
-        this.room.networkController.rtcp.workers.registerFunction("panorama", r=>{
-            logger.warn("receive panorama", r.uuid, r.pos),
-            r.uuid && eventsManager.remove(r.uuid, Codes.Success, r, !0),
+    bindListener(o) {
+        this.room.networkController.rtcp.workers.registerFunction("panorama", c=>{
+            var $;
+            logger.warn("receive panorama");
+            const {metadata: _} = c
+              , b = JSON.parse(String.fromCharCode.apply(null, _));
+            c.parsedMetaData = b;
+            const k = ($ = c.parsedMetaData.newUserStates) == null ? void 0 : $.find(_e=>_e.userId === this.room.userId)
+              , j = k == null ? void 0 : k.playerState.camera;
+            c.camera = j,
+            eventsManager.remove(c.parsedMetaData.traceIds[0], Codes.Success, c, !0),
             this.room.isFirstDataUsed || (this.room.isFirstDataUsed = !0,
-            this.handleReceivePanorama(r, this.room.options.camera).then(e))
+            this.handleReceivePanorama(c).then(o))
         }
         )
     }
-    access(e, t, r) {
-        const {camera: n, player: o, attitude: a, areaName: s, pathName: l, tag: u} = e;
+    access(o, s, c) {
+        this.isLoading = !0;
+        const {camera: _, player: b, pathId: k=this.room.currentState.pathId, tag: j, transferType: $} = o;
         return this.room.actionsHandler.requestPanorama({
-            camera: n,
-            player: o,
-            attitude: a,
-            areaName: s,
-            pathName: l,
-            tag: u
-        }, t, r).then(c=>this.handleReceivePanorama(c, o))
+            camera: _,
+            player: b,
+            pathId: k,
+            tag: j,
+            transferType: $
+        }, s, c).then(_e=>(this.isLoading = !1,
+        this.handleReceivePanorama(_e))).catch(_e=>(this.isLoading = !1,
+        Promise.reject(_e)))
     }
-    exit(e) {
-        const {camera: t, player: r, attitude: n, areaName: o, pathName: a} = e;
+    exit(o) {
+        const {camera: s, player: c, pathId: _=this.room.currentState.pathId, transferType: b} = o;
         return this.room.networkController.rtcp.workers.changePanoMode(!1),
         this.room.actionsHandler.changeRotationRenderType({
             renderType: RenderType.RotationVideo,
-            player: r,
-            camera: t,
-            attitude: n,
-            areaName: o,
-            pathName: a
-        }).then(()=>this.handleExitPanorama()).catch(s=>(this.room.networkController.rtcp.workers.changePanoMode(!0),
-        Promise.reject(s)))
+            player: c,
+            camera: s,
+            pathId: _,
+            transferType: b
+        }).then(()=>this.handleExitPanorama()).catch(k=>(this.room.networkController.rtcp.workers.changePanoMode(!0),
+        Promise.reject(k)))
     }
     handleExitPanorama() {
-        var e, t, r, n, o, a;
+        var o, s, c, _, b, k;
         this.room.isPano = !1,
         this._actived = !1,
-        (n = (e = this.room.sceneManager) == null ? void 0 : e.cameraComponent) == null || n.forceChangeSavedCameraPose({
-            position: (t = this.room._currentClickingState) == null ? void 0 : t.camera.position,
-            rotation: (r = this.room._currentClickingState) == null ? void 0 : r.camera.angle
+        (_ = (o = this.room.sceneManager) == null ? void 0 : o.cameraComponent) == null || _.forceChangeSavedCameraPose({
+            position: (s = this.room._currentClickingState) == null ? void 0 : s.camera.position,
+            rotation: (c = this.room._currentClickingState) == null ? void 0 : c.camera.angle
         }),
         this.room.sceneManager.changeVideoShaderForLowModel(),
-        (a = (o = this.room.sceneManager) == null ? void 0 : o.cameraComponent) == null || a.changeToThirdPersonView()
+        (k = (b = this.room.sceneManager) == null ? void 0 : b.cameraComponent) == null || k.changeToThirdPersonView()
     }
 }

+ 8 - 8
src/PathManager.js

@@ -2,13 +2,13 @@ import MotionType from "./enum/MotionType.js"
 
 export default class PathManager {
     constructor() {
-        this.currentArea = ''
-        this.currentPathName = ''
-        this.currentAttitude = ''
-        this.speed = 0
+        this.currentArea = "";
+        this.currentPathName = "";
+        this.currentAttitude = "";
+        this.speed = 0;
     }
-    getSpeed(e) {
-        const t = {
+    getSpeed(o) {
+        const s = {
             guangchang: {
                 [MotionType.Walk]: 17,
                 [MotionType.Run]: 51
@@ -30,8 +30,8 @@ export default class PathManager {
                 [MotionType.Run]: 25
             }
         }
-          , r = t[this.currentArea] || t.guangchang;
-        return this.speed = r[e] * 30,
+          , c = s[this.currentArea] || s.guangchang;
+        return this.speed = c[o] * 30,
         this.speed
     }
 }

+ 43 - 45
src/Pool.js

@@ -1,62 +1,60 @@
 import PoolObject from "./PoolObject.js"
 
 export default class Pool {
-    constructor(e, t, r, n, ...o) {
-        this.lastFree = null
-        this.nextFree = null
+    constructor(o, s, c, _, ...b) {
         this._pool = [],
-        this.objCreator = e,
-        this.objReseter = t;
-        for (let a = 0; a < n; a++)
-            this.addNewObject(this.newPoolObject(...o));
-        this.capacity = r
+        this.objCreator = o,
+        this.objReseter = s;
+        for (let k = 0; k < _; k++)
+            this.addNewObject(this.newPoolObject(...b));
+        this.capacity = c
     }
-    addNewObject(e) {
-        return this._pool.push(e),
-        this.release(e),
-        e
+    addNewObject(o) {
+        return this._pool.push(o),
+        this.release(o),
+        o
     }
-    release(e) {
-        e.free = !0,
-        e.nextFree = null,
-        e.previousFree = this.lastFree,
-        this.lastFree ? this.lastFree.nextFree = e : this.nextFree = e,
-        this.lastFree = e,
-        this.objReseter(e)
+    release(o) {
+        o.free = !0,
+        o.nextFree = null,
+        o.previousFree = this.lastFree,
+        this.lastFree ? this.lastFree.nextFree = o : this.nextFree = o,
+        this.lastFree = o,
+        this.objReseter(o)
     }
-    getFree(...e) {
-        const t = this.nextFree ? this.nextFree : this.addNewObject(this.newPoolObject(...e));
-        return t.free = !1,
-        this.nextFree = t.nextFree,
+    getFree(...o) {
+        const s = this.nextFree ? this.nextFree : this.addNewObject(this.newPoolObject(...o));
+        return s.free = !1,
+        this.nextFree = s.nextFree,
         this.nextFree || (this.lastFree = null),
-        t
+        s
     }
-    newPoolObject(...e) {
-        const t = this.objCreator(...e);
-        return new PoolObject(t,this.nextFree,this.lastFree)
+    newPoolObject(...o) {
+        const s = this.objCreator(...o);
+        return new PoolObject(s,this.nextFree,this.lastFree)
     }
     releaseAll() {
-        this._pool.forEach(e=>this.release(e))
+        this._pool.forEach(o=>this.release(o))
     }
-    clean(e=0, ...t) {
-        let r = this.nextFree;
-        if (!r)
+    clean(o=0, ...s) {
+        let c = this.nextFree;
+        if (!c)
             return;
-        let n = 0;
-        for (; r; )
-            n += 1,
-            r = r.nextFree;
-        let o = !1;
-        if (n > e && this._pool.length > this.capacity && (o = !0),
-        o)
-            for (r = this.nextFree; r; ) {
-                r.free = !1,
-                this.nextFree = r.nextFree;
-                const a = this._pool.indexOf(r);
-                this._pool.splice(a, 1),
+        let _ = 0;
+        for (; c; )
+            _ += 1,
+            c = c.nextFree;
+        let b = !1;
+        if (_ > o && this._pool.length > this.capacity && (b = !0),
+        b)
+            for (c = this.nextFree; c; ) {
+                c.free = !1,
+                this.nextFree = c.nextFree;
+                const k = this._pool.indexOf(c);
+                this._pool.splice(k, 1),
                 this.nextFree || (this.lastFree = null),
-                r == null || r.dispose(),
-                r = this.nextFree
+                c == null || c.dispose(),
+                c = this.nextFree
             }
     }
 }

+ 5 - 9
src/PoolObject.js

@@ -1,13 +1,9 @@
 export default class PoolObject {
-    constructor(e, t, r, n=!0) {
-        E(this, "data");
-        E(this, "nextFree");
-        E(this, "previousFree");
-        E(this, "free");
-        this.data = e,
-        this.nextFree = t,
-        this.previousFree = r,
-        this.free = n
+    constructor(o, s, c, _=!0) {
+        this.data = o,
+        this.nextFree = s,
+        this.previousFree = c,
+        this.free = _
     }
     dispose() {
         this.data && this.data instanceof BABYLON.Mesh && this.data.dispose(!0, !0),

+ 128 - 119
src/Preload.js

@@ -1,19 +1,21 @@
 import {reporter} from "./Reporter.js"
 import {modelTable} from "./ModelTable.js"
 import util from "./util.js"
-import {http1} from "./Http1.js"
-import InternalError from "./error/InternalError.js"
+import {http} from "./Http.js"
+import AssetsStorage from "./AssetsStorage.js"
 import axios from "axios";
 import Logger from "./Logger.js"
 import PreloadCanceledError from "./error/PreloadCanceledError.js"
 import ParamError from "./error/ParamError.js"
+import {tracker} from "./Tracker.js"
 
 const logger = new Logger('preload')
 export default class Preload {
-    constructor(e) {
-        this.config = null
-        this.allKeys = []
+    constructor(o) {
+        this.config = null;
+        this.allKeys = [];
         this.oldResourcesDeleted = !1;
+        this.concurrence = 10;
         this.requests = {
             simple: {
                 stopped: !0,
@@ -28,167 +30,174 @@ export default class Preload {
                 requests: {}
             }
         };
-        this.modelManager = e,
-        this.init(e.appId)
+        this.onGetPreloadTypeFunc = null;;
+        this.modelManager = o,
+        this.init(o.appId)
+    }
+    onGetPreloadType(o) {
+        this.onGetPreloadTypeFunc = o
     }
-    init(e) {
+    init(o) {
         reporter.updateBody({
-            appId: e
+            appId: o
+        }),
+        tracker.updateHeader({
+            appId: o
         })
     }
-    static getTimeoutBySize(e) {
-        return e ? e < 500 * 1e3 ? 30 * 1e3 : e < 1e3 * 1e3 ? 60 * 1e3 : 100 * 1e3 : 100 * 1e3
+    static getTimeoutBySize(o) {
+        return o ? o < 500 * 1e3 ? 30 * 1e3 : o < 1e3 * 1e3 ? 60 * 1e3 : 100 * 1e3 : 100 * 1e3
     }
-    async getConfig(e) {
+    async getConfig() {
         if (this.config)
             return this.config;
-        const {preload: t} = await this.modelManager.requestConfig();
-        return t ? (this.config = t,
-        Promise.resolve(t)) : Promise.reject("no preload config")
+        const {preload: o} = await this.modelManager.requestConfig();
+        return o ? (this.config = o,
+        Promise.resolve(o)) : Promise.reject("no preload config")
     }
     async getAllKeys() {
+        if (!AssetsStorage.USE_INDEXEDDB)
+            return [];
         if (this.allKeys.length)
             return this.allKeys;
         try {
-            const e = await modelTable.getAllKeys();
-            this.allKeys = e;
-            return e
+            const o = await modelTable.getAllKeys()._timeout(3e3, new TimeoutError("db getAllKeys timeout"));
+            return this.allKeys = o,
+            o
         } catch {
-            const t = "preload getAllKeys error";
-            return logger.error(t),
-            Promise.reject(t)
+            const s = "preload getAllKeys error";
+            return logger.error(s),
+            Promise.reject(s)
         }
     }
-    stop(e) {
-        e === "serverless" && (e = "observer"),
-        this.requests[e].stopped = !0;
-        const t = this.requests[e].requests;
-        Object.keys(t).forEach(r=>{
-            http1.canceler.removePending(r),
-            delete t[r]
+    stop(o) {
+        o === "serverless" && (o = "observer"),
+        this.requests[o].stopped = !0;
+        const s = this.requests[o].requests;
+        Object.keys(s).forEach(c=>{
+            http.canceler.removePending(c),
+            delete s[c]
         }
         )
     }
-    clearPreload(e) {
-        this.requests[e].stopped = !1,
+    clearPreload(o) {
+        this.requests[o].stopped = !1,
         this.allKeys = []
     }
-    async start(e, t, r) {
-        let n = Date.now()
-          , o = 0;
+    async start(o, s, c) {
+        const {filterCallback: _, preloadedList: b} = c || {};
+        let k = Date.now()
+          , j = 0;
         try {
-            if (e === "serverless" && (e = "observer"),
-            !this.requests[e])
-                return Promise.reject(new ParamError("invalid stage name: " + e));
-            this.clearPreload(e);
-            const a = await this.getConfig(e);
-            const s = await this.getAllKeys();
+            if (o === "serverless" && (o = "observer"),
+            !this.requests[o])
+                return Promise.reject(new ParamError("invalid stage name: " + o));
+            this.clearPreload(o);
+            const $ = await this.getConfig();
+            let _e = [];
+            const et = {}
+              , tt = $.assetList.map(nt=>nt.assetUrl);
             try {
-                await this.deleteOldResources(a.assetUrls.map(d=>d.url), s)
-            } catch (d) {
-                logger.error(d)
+                _e = await this.getAllKeys(),
+                _e.push(...b || []),
+                await this.deleteOldResources(tt, _e)
+            } catch {
+                logger.error("getAllKeys error, deleting db"),
+                await modelTable.clearDataBase()
             }
-            const {baseUrls: l, assetUrls: u, observeUrls: c} = a;
-            let h;
-            switch (e) {
-            case "simple":
-                h = l;
-                break;
-            case "observer":
-                h = u;
-                break;
-            case "full":
-                h = u;
-                break;
-            default:
-                h = u
+            const rt = $.assetList;
+            _e.forEach(nt=>{
+                et[nt] = !0
             }
-            let f = h.filter(d=>!s.includes(d.url));
-            r && isFunction(r) && (f = f.filter(r));
-            o = f.length;
-            logger.debug("keysNeedToPreload", f);
-            f.length || t && t(h.length, h.length);
-            n = Date.now();
-            await this._preload(e, f, t);
+            );
+            let it = rt.filter(nt=>!et[nt.assetUrl]);
+            _ && isFunction(_) && (it = it.filter(_)),
+            j = it.length,
+            logger.debug("keysNeedToPreload", it),
+            logger.warn("preloadStart", it.length),
+            it.length || s && s(rt.length, rt.length),
+            this.invokeOnGetPreloadType(_e.length, it.length),
+            k = Date.now(),
+            await this._preload(o, it, s),
             logger.infoAndReportMeasurement({
-                tag: e,
-                type: "assetsPreload",
-                extraData: {
-                    total: o
+                tag: o,
+                startTime: k,
+                metric: "assetsPreload",
+                extra: {
+                    total: j
                 }
             });
             return
-        } catch (a) {
-            let s = a;
-            return (this.requests[e].stopped || axios.isCancel(a)) && (s = new PreloadCanceledError),
+        } catch ($) {
+            let _e = $;
+            return (this.requests[o].stopped || axios.isCancel($)) && (_e = new PreloadCanceledError),
             logger.infoAndReportMeasurement({
-                tag: e,
-                type: "assetsPreload",
-                error: s,
-                options: {
-                    immediate: !0
+                tag: o,
+                startTime: k,
+                metric: "assetsPreload",
+                extra: {
+                    total: j
                 },
-                extraData: {
-                    total: o
+                error: _e,
+                reportOptions: {
+                    immediate: !0
                 }
             }),
-            Promise.reject(s)
+            Promise.reject(_e)
         }
     }
-    deleteOldResources(e, t) {
+    invokeOnGetPreloadType(o, s) {
+        let c = "increment";
+        o === 0 ? c = "fresh" : s || (c = "completed"),
+        this.onGetPreloadTypeFunc && this.onGetPreloadTypeFunc(c)
+    }
+    async deleteOldResources(o, s) {
         if (!this.oldResourcesDeleted)
             this.oldResourcesDeleted = !0;
         else
             return Promise.resolve();
-        const r = t.filter(n=>!e.includes(n));
-        return logger.debug("keysNeedToDelete", r),
-        logger.warn("keysNeedToDelete", r.length),
-        Promise.all(r.map(n=>modelTable.delete(n)))
+        const c = {};
+        o.forEach(k=>{
+            c[k] = !0
+        }
+        );
+        const _ = s.filter(k=>!c[k]);
+        logger.debug("keysNeedToDelete", _),
+        logger.warn("keysNeedToDelete", _.length);
+        const b = Promise.all(_.map(k=>modelTable.delete(k)));
+        try {
+            await b
+        } catch (k) {
+            logger.error("deleteOldResources error", k)
+        }
     }
-    async _preload(e, t, r) {
-        const n = t.length;
-        if (!n)
+    async _preload(o, s, c) {
+        const _ = s.length;
+        if (!_)
             return Promise.resolve();
-        let o = 0;
-        const a = window.setInterval(()=>{
-            r && r(o, n),
-            o >= n && window.clearInterval(a)
+        let b = 0;
+        const k = window.setInterval(()=>{
+            c && c(b, _),
+            b >= _ && window.clearInterval(k)
         }
         , 1e3);
-        return util.mapLimit(t, 10, async s=>{
-            const {size: l, url: u} = s;
-            return this.requests[e].stopped ? Promise.reject(new PreloadCanceledError) : http1.get({
-                url: u,
-                timeout: Preload.getTimeoutBySize(l),
+        return mapLimit(s, this.concurrence, async j=>{
+            const {size: $, assetUrl: _e} = j;
+            return this.requests[o].stopped ? Promise.reject(new PreloadCanceledError) : AssetsStorage.requestAndPut({
+                url: _e,
+                timeout: Preload.getTimeoutBySize($),
                 responseType: "blob",
                 retry: 2,
                 beforeRequest: ()=>{
-                    this.requests[e].requests[u] = !0
-                }
-            }).then(async c=>{
-                const h = c.data;
-                if (!(h instanceof Blob))
-                    return logger.error("request blob failed, type:", typeof h, u),
-                    Promise.reject("request blob failed " + u);
-                const f = await blobToDataURI(h);
-                try {
-                    await modelTable.put({
-                        url: u,
-                        model: f
-                    });
-                    return
-                } catch (d) {
-                    return logger.error("unable to add data to indexedDB", d),
-                    Promise.reject(new InternalError("preload db error"))
+                    this.requests[o].requests[_e] = !0
                 }
+            }).then(()=>{
+                b++,
+                delete this.requests[o].requests[_e]
             }
-            ).then(()=>{
-                o++,
-                delete this.requests[e].requests[u]
-            }
-            , c=>(delete this.requests[e].requests[u],
-            window.clearInterval(a),
-            Promise.reject(c)))
+            , et=>(delete this.requests[o].requests[_e],
+            window.clearInterval(k),
+            Promise.reject(et)))
         }
         )
     }

+ 13 - 12
src/Queue.js

@@ -1,20 +1,21 @@
 export default class Queue {
-    constructor() {
-        E(this, "queue", []);
-        E(this, "currentAction")
+    constructor(o) {
+        this.queue = [];
+        this.currentAction = null;
+        this.avatar = o
     }
-    async append(e) {
-        var t, r;
-        this.queue.length === 0 || ((t = this.currentAction) == null ? void 0 : t.type) === e.type && this.queue.length === 1 ? (this.queue = [],
-        this.queue.push(e),
-        await this.go()) : (((r = this.queue[this.queue.length - 1]) == null ? void 0 : r.type) === e.type && this.queue.pop(),
-        this.queue.push(e))
+    async append(o) {
+        var s, c;
+        this.avatar.isSelf || (this.queue.length === 0 || ((s = this.currentAction) == null ? void 0 : s.type) === o.type && this.queue.length === 1 ? (this.queue = [],
+        this.queue.push(o),
+        await this.go()) : (((c = this.queue[this.queue.length - 1]) == null ? void 0 : c.type) === o.type && this.queue.pop(),
+        this.queue.push(o)))
     }
     async go() {
         if (this.queue.length !== 0) {
-            const e = this.queue[0];
-            this.currentAction = e,
-            await e.action(),
+            const o = this.queue[0];
+            this.currentAction = o,
+            await this.avatar.statusSync(o.userState),
             this.currentAction = void 0,
             this.queue.splice(0, 1),
             await this.go()

Diferenças do arquivo suprimidas por serem muito extensas
+ 59 - 48
src/Reporter.js


+ 76 - 74
src/RotationEvent.js

@@ -1,106 +1,108 @@
 export default class RotationEvent {
-    constructor(e) {
-        E(this, "touchStartX");
-        E(this, "touchStartY");
-        E(this, "handelResize");
-        E(this, "_room");
-        E(this, "_canvas");
-        E(this, "handleTouchStart", e=>{
-            const t = e.touches[0];
-            this.touchStartX = t.pageX,
-            this.touchStartY = t.pageY,
+    constructor(o) {
+        this.touchStartX = null;
+        this.touchStartY = null;
+        this.handelResize = null;
+        this._canvas = null;
+        this.isResponseRotating = !0;
+        this.handleTouchStart = o=>{
+            if (!this.isResponseRotating)
+                return;
+            const s = o.touches[0];
+            this.touchStartX = s.pageX,
+            this.touchStartY = s.pageY,
             this._room.emit("touchStart", {
-                event: e
+                event: o
             })
-        }
-        );
-        E(this, "handleMouseDown", e=>{
-            this.touchStartX = e.pageX,
-            this.touchStartY = e.pageY
-        }
-        );
-        E(this, "handleMouseMove", e=>{
-            if (!this.touchStartX || !this.touchStartY)
+        };
+        this.handleMouseDown = o=>{
+            !this.isResponseRotating || (this.touchStartX = o.pageX,
+            this.touchStartY = o.pageY)
+        };
+        this.handleMouseMove = o=>{
+            if (!this.isResponseRotating || !this.touchStartX || !this.touchStartY)
                 return;
-            const t = e.pageX
-              , r = e.pageY
-              , n = t - this.touchStartX
-              , o = r - this.touchStartY
-              , a = this._room.options.canvas.offsetHeight
-              , s = this._room.options.canvas.offsetWidth;
-            // 后端定,鼠标移动一个canvas width转动90度。*2移动距离加倍,所以前端实际会转180度
-            let l = 2 * o / a
-              , u = 2 * n / s;
-            // 瞬时最大不超过90度
-            l > 1 && (l = 1),
-            u > 1 && (u = 1),
+            const s = o.pageX
+              , c = o.pageY
+              , _ = s - this.touchStartX
+              , b = c - this.touchStartY
+              , k = this._room.options.canvas.offsetHeight
+              , j = this._room.options.canvas.offsetWidth;
+            let $ = 2 * b / k
+              , _e = 2 * _ / j;
+            $ > 1 && ($ = 1),
+            _e > 1 && (_e = 1),
             this._room.actionsHandler.rotate({
-                pitch: l,
-                yaw: u
+                pitch: $,
+                yaw: _e
             }),
-            this.touchStartX = t,
-            this.touchStartY = r
-        }
-        );
-        E(this, "handleMouseUp", ()=>{
-            this.touchStartX = void 0,
-            this.touchStartY = void 0
-        }
-        );
-        E(this, "handleTouchMove", e=>{
-            if (!this.touchStartX || !this.touchStartY)
+            this.touchStartX = s,
+            this.touchStartY = c
+        };
+        this.handleMouseUp = o=>{
+            !this.isResponseRotating || (this.touchStartX = void 0,
+            this.touchStartY = void 0,
+            this._room.emit("mouseUp", {
+                event: o
+            }))
+        };
+        this.handleTouchMove = o=>{
+            if (!this.isResponseRotating || !this.touchStartX || !this.touchStartY)
                 return;
-            const t = e.touches[0]
-              , r = t.pageX
-              , n = t.pageY
-              , o = r - this.touchStartX
-              , a = n - this.touchStartY
-              , s = this._room.options.canvas.offsetHeight
-              , l = this._room.options.canvas.offsetWidth;
-            let u = 2 * a / s
-              , c = 2 * o / l;
-            u > 1 && (u = 1),
-            c > 1 && (c = 1),
+            const s = o.touches[0]
+              , c = s.pageX
+              , _ = s.pageY
+              , b = c - this.touchStartX
+              , k = _ - this.touchStartY
+              , j = this._room.options.canvas.offsetHeight
+              , $ = this._room.options.canvas.offsetWidth;
+            let _e = 2 * k / j
+              , et = 2 * b / $;
+            _e > 1 && (_e = 1),
+            et > 1 && (et = 1),
             this._room.actionsHandler.rotate({
-                pitch: u,
-                yaw: c
+                pitch: _e,
+                yaw: et
             }),
-            this.touchStartX = r,
-            this.touchStartY = n,
+            this.touchStartX = c,
+            this.touchStartY = _,
             this._room.emit("touchMove", {
-                pitch: u,
-                yaw: c,
-                event: e
+                pitch: _e,
+                yaw: et,
+                event: o
             })
-        }
-        );
-        E(this, "handleTouchEnd", e=>{
-            this._room.emit("touchEnd", {
-                event: e
+        };
+
+        this.handleTouchEnd = o=>{
+            !this.isResponseRotating || this._room.emit("touchEnd", {
+                event: o
             })
-        }
-        );
-        this._room = e,
-        this._canvas = e.canvas,
+        };
+        this._room = o,
+        this._canvas = o.canvas,
         this.handelResize = this.reiszeChange()
     }
     init() {
         this._canvas.addEventListener("touchstart", this.handleTouchStart),
         this._canvas.addEventListener("touchmove", this.handleTouchMove),
         this._canvas.addEventListener("touchend", this.handleTouchEnd),
+        this._canvas.addEventListener("touchcancel", this.handleTouchEnd),
         this._room.scene.preventDefaultOnPointerDown = !1,
         this._room.scene.preventDefaultOnPointerUp = !1,
         this._canvas.addEventListener("mousedown", this.handleMouseDown),
         this._canvas.addEventListener("mousemove", this.handleMouseMove),
-        this._canvas.addEventListener("mouseup", this.handleMouseUp)
+        this._canvas.addEventListener("mouseup", this.handleMouseUp),
+        this._canvas.addEventListener("mouseleave", this.handleMouseUp)
     }
     clear() {
         this._canvas.removeEventListener("touchstart", this.handleTouchStart),
         this._canvas.removeEventListener("touchmove", this.handleTouchMove),
         this._canvas.removeEventListener("touchend", this.handleTouchEnd),
+        this._canvas.removeEventListener("touchcancel", this.handleTouchEnd),
         this._canvas.removeEventListener("mousedown", this.handleMouseDown),
         this._canvas.removeEventListener("mousemove", this.handleMouseMove),
-        this._canvas.removeEventListener("mouseup", this.handleMouseUp)
+        this._canvas.removeEventListener("mouseup", this.handleMouseUp),
+        this._canvas.removeEventListener("mouseleave", this.handleMouseUp)
     }
     reiszeChange() {
         window.addEventListener("resize", ()=>{}

+ 142 - 122
src/Rtcp.js

@@ -1,184 +1,198 @@
 import Workers from "./Workers.js"
 import Heartbeat from "./Heartbeat.js"
+import XStream from "./XStream.js"
 import Logger from "./Logger.js"
+import InternalError from "./error/InternalError.js"
 
 const logger = new Logger('rtcp')
 
 export default class Rtcp extends EventEmitter {
-    constructor(e) {
-        
+    constructor(s) {
         super();
-        E(this, "connection", null);
-        E(this, "inputChannel", null);
-        E(this, "mediaStream");
-        E(this, "socket");
-        E(this, "connected", !1);
-        E(this, "candidates", []);
-        E(this, "isAnswered", !1);
-        E(this, "isFlushing", !1);
-        E(this, "inputReady", !1);
-        E(this, "workers");
-        E(this, "actived", !0);
-        E(this, "heartbeat");
-        E(this, "onIcecandidate", e=>{
-            if (e.candidate != null) {
-                const t = JSON.stringify(e.candidate);
-                logger.debug(`Got ice candidate: ${t}`),
+        this.connection = null;
+        this.inputChannel = null;
+        this.xStream = null;
+        this.mediaStream = null;
+        this.localStream = null;
+        this.socket = null;
+        this.connected = !1;
+        this.candidates = [];
+        this.isAnswered = !1;
+        this.isFlushing = !1;
+        this.inputReady = !1;
+        this.workers = null;
+        this.actived = !0;
+        this.heartbeat = null;
+
+        this.onNegotiationAnswer = async s=>{
+            var b;
+            const c = JSON.parse(atob(s))
+              , _ = new RTCSessionDescription(c);
+            logger.debug("on negotiation answer is triggered ", _.sdp),
+            logger.debug("set remote description answer is ", _.sdp),
+            (b = this.connection) == null || b.setRemoteDescription(_)
+        };
+
+        this.onNegotiationNeeded = async s=>{
+            this.network.socket.send({
+                id: "offer",
+                data: ""
+            })
+        };
+        this.onIcecandidate = s=>{
+            if (s.candidate != null) {
+                const c = JSON.stringify(s.candidate);
+                logger.debug(`Got ice candidate: ${c}`),
                 this.network.socket.send({
                     id: "ice_candidate",
-                    data: btoa(t)
+                    data: btoa(c)
                 })
             }
-        }
-        );
-        E(this, "onIcecandidateerror", e=>{
-            logger.error("onicecandidateerror", e.errorCode, e.errorText, e)
-        }
-        );
-        E(this, "onIceStateChange", e=>{
-            switch (e.target.iceGatheringState) {
+        };
+
+        this.onIcecandidateerror = s=>{
+            logger.error("onicecandidateerror", s.errorCode, s.errorText, s)
+        };
+        this.onIceStateChange = s=>{
+            switch (s.target.iceGatheringState) {
             case "gathering":
                 logger.info("ice gathering");
                 break;
             case "complete":
                 logger.info("Ice gathering completed")
             }
-        }
-        );
-        E(this, "onIceConnectionStateChange", ()=>{
+        };
+        this.onIceConnectionStateChange = ()=>{
             if (!!this.connection)
-            {
-                logger.info(`iceConnectionState: ${this.connection.iceConnectionState}`);
-                switch (this.connection.iceConnectionState) {
-                    case "connected":
+                switch (logger.warn(`iceConnectionState: ${this.connection.iceConnectionState}`),
+                this.connection.iceConnectionState) {
+                case "connected":
                     {
                         this.connected = !0;
                         break
                     }
-                    case "disconnected":
+                case "disconnected":
                     {
                         this.connected = !1,
                         this.emit("rtcDisconnected");
                         break
                     }
-                    case "failed":
+                case "failed":
                     {
                         this.emit("rtcDisconnected"),
                         this.connected = !1;
                         break
                     }
                 }
-            }
-        }
-        );
-        E(this, "setRemoteDescription", async(e,t)=>{
-            var a, s, l;
+        };
+        this.setRemoteDescription = async s=>{
+            var k, j, $;
             if (!this.connection)
                 return;
-            const r = JSON.parse(atob(e))
-              , n = new RTCSessionDescription(r);
-            await this.connection.setRemoteDescription(n);
-            const o = await this.connection.createAnswer();
-            if (o.sdp = (a = o.sdp) == null ? void 0 : a.replace(/(a=fmtp:111 .*)/g, "$1;stereo=1;sprop-stereo=1"),
-            ((l = (s = o.sdp) == null ? void 0 : s.match(/a=mid:1/g)) == null ? void 0 : l.length) == 2) {
-                const u = o.sdp.lastIndexOf("a=mid:1");
-                o.sdp = o.sdp.slice(0, u) + "a=mid:2" + o.sdp.slice(u + 7)
+            let c = {};
+            try {
+                c = JSON.parse(atob(s))
+            } catch (_e) {
+                logger.error(_e, s),
+                this.emit("rtcDisconnected", new InternalError("invalid sdp"));
+                return
+            }
+            const _ = new RTCSessionDescription(c);
+            logger.debug("breakpiont going to set remote description offer is ", _.sdp),
+            await this.connection.setRemoteDescription(_);
+            const b = await this.connection.createAnswer();
+            if (b.sdp = (k = b.sdp) == null ? void 0 : k.replace(/(a=fmtp:111 .*)/g, "$1;stereo=1;sprop-stereo=1"),
+            (($ = (j = b.sdp) == null ? void 0 : j.match(/a=mid:1/g)) == null ? void 0 : $.length) == 2) {
+                const _e = b.sdp.lastIndexOf("a=mid:1");
+                b.sdp = b.sdp.slice(0, _e) + "a=mid:2" + b.sdp.slice(_e + 7)
             }
             try {
-                await this.connection.setLocalDescription(o)
-            } catch (u) {
-                logger.error("error", u)
+                await this.connection.setLocalDescription(b)
+            } catch (_e) {
+                logger.error("error", _e)
             }
             this.isAnswered = !0,
             this.network.rtcp.flushCandidate(),
             this.network.socket.send({
                 id: "answer",
-                data: btoa(JSON.stringify(o))
-            }),
-            t.srcObject = this.mediaStream
-        }
-        );
-        E(this, "flushCandidate", ()=>{
+                data: btoa(JSON.stringify(b))
+            })
+        };
+
+        this.flushCandidate = ()=>{
             this.isFlushing || !this.isAnswered || (this.isFlushing = !0,
-            this.candidates.forEach(e=>{
-                const t = atob(e)
-                  , r = JSON.parse(t);
-                if (/172\./.test(r.candidate))
+            this.candidates.forEach(s=>{
+                const c = atob(s)
+                  , _ = JSON.parse(c);
+                if (/172\./.test(_.candidate))
                     return;
-                const n = new RTCIceCandidate(r);
-                this.connection && this.connection.addIceCandidate(n).then(()=>{}
-                , o=>{
-                    logger.info("add candidate failed", o)
+                const b = new RTCIceCandidate(_);
+                this.connection && this.connection.addIceCandidate(b).then(()=>{}
+                , k=>{
+                    logger.info("add candidate failed", k)
                 }
                 )
             }
             ),
             this.isFlushing = !1)
-        }
-        );
-        E(this, "input", e=>{
-            var o = this.inputChannel;
-			if(!this.actived || !this.inputChannel || this.inputChannel.readyState === "open"){
-				if(o != null){
-					//console.log('发送webrtc数据:'+e)
-					o.send(e)
-				}
-			}
-        }
-        );
-        this.network = e,
-        this.workers = new Workers(this,logger),
-        this.workers.registerLogger(logger),
-        this.workers.registerFunction("data", t=>{
-            this.emit("data", t)
+        };
+        this.input = s=>{
+            var c;
+            !this.actived || !this.inputChannel || this.inputChannel.readyState === "open" && ((c = this.inputChannel) == null || c.send(s))
+        };
+
+        this.network = s,
+        this.workers = new Workers(this,new Logger("decode")),
+        this.workers.registerLogger(new Logger("decode")),
+        this.workers.registerFunction("data", c=>{
+            this.emit("data", c)
         }
         ),
         this.heartbeat = new Heartbeat({
-            ping: t=>{
-                e.room.actionsHandler.echo(t)
+            ping: c=>{
+                s.room.actionsHandler.echo(c)
             }
             ,
-            pong(t, r) {
-                var n;
-                r && t > 500 && logger.warn(`high hb value ${t}, traceId:` + r),
-                (n = e.room.stats) == null || n.assign({
-                    hb: t
+            pong(c, _) {
+                var b;
+                _ && c > 500 && logger.warn(`high hb value ${c}, traceId:` + _),
+                (b = s.room.stats) == null || b.assign({
+                    hb: c
                 })
             }
         })
     }
-
-   
-
-    start() {
-        this.connection = new RTCPeerConnection;
-        const e = Date.now();
-        this.connection.ondatachannel = t=>{
-            logger.info(`ondatachannel: ${t.channel.label}`);
-           
-            this.inputChannel = t.channel;
+    async start() {
+        this.connection = new RTCPeerConnection,
+        this.xStream = new XStream(this.connection);
+        const s = Date.now();
+        this.connection.ondatachannel = c=>{
+            logger.info(`ondatachannel: ${c.channel.label}`),
+            this.inputChannel = c.channel,
             this.inputChannel.onopen = ()=>{
-                var r;
-                logger.info("The input channel has opened, id:", (r = this.inputChannel) == null ? void 0 : r.id),
+                var _;
+                logger.info("The input channel has opened, id:", (_ = this.inputChannel) == null ? void 0 : _.id),
                 this.inputReady = !0,
                 this.emit("rtcConnected"),
                 this.network.room.currentNetworkOptions.reconnect || (logger.infoAndReportMeasurement({
-                    type: "datachannelOpenedAt",
+                    metric: "datachannelOpenedAt",
+                    startTime: this.network.room._startTime,
                     group: "joinRoom"
                 }),
                 logger.infoAndReportMeasurement({
-                    type: "datachannelOpenedCost",
+                    metric: "datachannelOpenedCost",
+                    startTime: s,
                     group: "joinRoom"
                 }))
-                console.log('this.inputChannel',this.inputChannel)
             }
             ,
             this.inputChannel.onclose = ()=>{
-                var r;
-                return logger.info("The input channel has closed, id:", (r = this.inputChannel) == null ? void 0 : r.id)
-            },
-            this.inputChannel.onmessage = r=>{
-                this.workers.dataHandle(r.data)
+                var _;
+                return logger.info("The input channel has closed, id:", (_ = this.inputChannel) == null ? void 0 : _.id)
+            }
+            ,
+            this.inputChannel.onmessage = _=>{
+                this.workers.dataHandle(_.data)
             }
         }
         ,
@@ -186,6 +200,7 @@ export default class Rtcp extends EventEmitter {
         this.connection.onicegatheringstatechange = this.onIceStateChange,
         this.connection.onicecandidate = this.onIcecandidate,
         this.connection.onicecandidateerror = this.onIcecandidateerror,
+        this.connection.onnegotiationneeded = this.onNegotiationNeeded,
         this.network.socket.send({
             id: "init_webrtc",
             data: JSON.stringify({
@@ -193,24 +208,29 @@ export default class Rtcp extends EventEmitter {
             })
         })
     }
-    addCandidate(e) {
-        e === "" ? this.network.rtcp.flushCandidate() : this.candidates.push(e)
+    addCandidate(s) {
+        s === "" ? this.network.rtcp.flushCandidate() : this.candidates.push(s)
     }
     disconnect() {
-        var i, o, s;
-        this.heartbeat.stop(), logger.info("ready to close datachannel, id", (i = this.inputChannel) == null ? void 0 : i.id), (o = this.inputChannel) == null || o.close(), (s = this.connection) == null || s.close(), this.connection = null, this.inputChannel = null
+        var s, c, _;
+        this.heartbeat.stop(),
+        logger.info("ready to close datachannel, id", (s = this.inputChannel) == null ? void 0 : s.id),
+        (c = this.inputChannel) == null || c.close(),
+        (_ = this.connection) == null || _.close(),
+        this.connection = null,
+        this.inputChannel = null
     }
-    sendStringData(e) {
-        this.input(e)
+    sendStringData(s) {
+        this.input(s)
     }
-    sendData(e) {
-        let t = "";
+    sendData(s) {
+        let c = "";
         try {
-            t = JSON.stringify(e)
-        } catch (r) {
-            logger.error(r);
+            c = JSON.stringify(s)
+        } catch (_) {
+            logger.error(_);
             return
         }
-        this.input(t)
+        this.input(c)
     }
 }

+ 16 - 17
src/RunTimeArray.js

@@ -1,38 +1,37 @@
 export default class RunTimeArray {
     constructor() {
-        E(this, "circularData");
         this.circularData = []
     }
-    add(e) {
+    add(o) {
         this.circularData.length > 1e3 && this.circularData.shift(),
-        this.circularData.push(e)
+        this.circularData.push(o)
     }
     getAvg() {
-        let e = 0;
-        for (let t = 0; t < this.circularData.length; t++)
-            e += this.circularData[t];
+        let o = 0;
+        for (let s = 0; s < this.circularData.length; s++)
+            o += this.circularData[s];
         return {
-            sum: e,
-            avg: e / this.circularData.length || 0
+            sum: o,
+            avg: o / this.circularData.length || 0
         }
     }
     getMax() {
-        let e = 0;
-        for (let t = 0; t < this.circularData.length; t++)
-            e < this.circularData[t] && (e = this.circularData[t]);
-        return e || 0
+        let o = 0;
+        for (let s = 0; s < this.circularData.length; s++)
+            o < this.circularData[s] && (o = this.circularData[s]);
+        return o || 0
     }
     clear() {
         this.circularData = []
     }
     getStat() {
-        const e = this.getAvg()
-          , t = {
-            sum: e.sum,
-            avg: e.avg,
+        const o = this.getAvg()
+          , s = {
+            sum: o.sum,
+            avg: o.avg,
             max: this.getMax()
         };
         return this.clear(),
-        t
+        s
     }
 }

+ 19 - 16
src/SecondArray.js

@@ -2,32 +2,35 @@ export default class SecondArray {
     constructor() {
         this.circularData = []
     }
-    add(e) {
-        this.circularData.push(e)
+    add(o) {
+        this.circularData.push(o)
     }
     getAvg() {
-        let e = 0;
-        for (let i = 0; i < this.circularData.length; i++) e += this.circularData[i];
+        let o = 0;
+        for (let s = 0; s < this.circularData.length; s++)
+            o += this.circularData[s];
         return {
-            sum: e,
-            avg: e / this.circularData.length || 0
+            sum: o,
+            avg: o / this.circularData.length || 0
         }
     }
     getMax() {
-        let e = 0;
-        for (let i = 0; i < this.circularData.length; i++) e < this.circularData[i] && (e = this.circularData[i]);
-        return e || 0
+        let o = 0;
+        for (let s = 0; s < this.circularData.length; s++)
+            o < this.circularData[s] && (o = this.circularData[s]);
+        return o || 0
     }
     clear() {
         this.circularData = []
     }
     getStat() {
-        const e = this.getAvg(),
-            i = {
-                sum: e.sum,
-                avg: e.avg,
-                max: this.getMax()
-            };
-        return this.clear(), i
+        const o = this.getAvg()
+          , s = {
+            sum: o.sum,
+            avg: o.avg,
+            max: this.getMax()
+        };
+        return this.clear(),
+        s
     }
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 120 - 145
src/Signal.js


+ 247 - 286
src/Socket.js

@@ -5,319 +5,280 @@ import { reporter } from "./Reporter.js";
 import util from "./util.js";
 import InternalError from "./error/InternalError.js";
 import Logger from "./Logger.js";
+import {tracker} from "./Tracker.js"
 
 const logger = new Logger("ws");
 export default class Socket extends EventEmitter {
-  constructor(e) {
+  constructor(s) {
     super();
-    E(this, "_ws");
-    E(this, "_openTimer");
-    E(this, "connected", !1);
-    E(this, "_hasTimeout", !1);
-    E(this, "heartbeat");
-    E(this, "latency", (e, t) =>
-      this.send({
+    this._ws = null;
+    this._openTimer = null;
+    this.connected = !1;
+    this._hasTimeout = !1;
+    this.heartbeat = null;
+    this.latency = (s,c)=>this.send({
         id: "checkLatency",
-        data: JSON.stringify(e),
-        packet_id: t,
-      })
-    );
-    E(this, "send", (e) => {
-      if (this.wsNoReady()) {
-        return;
-      }
-      const t = JSON.stringify(e);
-      e.id !== "heartbeat" && logger.info("send ws frame", t);
-      this._ws.send(t);
-      // console.log('socket发送数据:'+t)
-    });
-    E(this, "startGame", () => {
-      const {
-        roomId: e,
-        userId: t,
-        avatarId: r,
-        skinId: n,
-        role: o,
-        avatarComponents: a,
-        versionId: s,
-        rotationRenderType: l,
-        isAllSync: u,
-        nickname: c,
-        avatarScale: h,
-        appId: f,
-        camera: d,
-        player: _,
-        firends: g,
-        syncByEvent: m,
-        areaName: v,
-        attitude: y,
-        pathName: b,
-        person: T,
-        roomTypeId: C = "",
-        syncToOthers: A,
-        hasAvatar: S,
-        prioritySync: P,
-        extra: R = {},
-        removeWhenDisconnected: M,
-      } = this.network.room.currentNetworkOptions;
-      R.removeWhenDisconnected = M;
-      const x = {
-        id: "start",
-        room_id: e,
-        user_id: t,
-        trace_id: util.uuid(),
-        data: JSON.stringify({
-          avatar_components: JSON.stringify(a),
-          avatar_id: r,
-          skin_id: n,
-          is_host: o ? o == "host" : !0,
-          skin_data_version: n !== void 0 && s !== void 0 ? n + s : void 0,
-          rotation_render_type: l,
-          is_all_sync: u,
-          nick_name: encodeURIComponent(c || ""),
-          app_id: f,
-          camera: d,
-          player: _,
-          person: T,
-          firends: JSON.stringify(g),
-          sync_by_event: m,
-          area_name: v,
-          path_name: b,
-          attitude: y,
-          room_type_id: C,
-          syncToOthers: A,
-          hasAvatar: S,
-          avatarSize: h,
-          prioritySync: P,
-          extra: JSON.stringify(R),
-        }),
-      };
-      this.send(x);
-      const mt = JSON.parse(x.data);
-      delete mt.token;
-      logger.infoAndReportMeasurement({
-        type: "startGame",
-        extraData: mt
-      });
+        data: JSON.stringify(s),
+        packet_id: c
     });
-    (this.network = e),
-      (this.heartbeat = new Heartbeat({
-        ping: (t) => {
-          var r;
-          if (!this.connected) {
-            this.heartbeat.stop(),
-              (r = e.room.stats) == null ||
-                r.assign({
-                  rtt: 0,
-                });
+    this.send = s=>{
+        if (this.wsNoReady())
             return;
-          }
-          this.send({
-            id: "heartbeat",
-            data: t,
-          });
-        },
-        pong(t) {
-          var r;
-          (r = e.room.stats) == null ||
-            r.assign({
-              rtt: t,
-            });
-        },
-      }));
+        const c = JSON.stringify(s);
+        s.id !== "heartbeat" && logger.info("send ws frame", c),
+        this._ws.send(c)
+    };
+    this.startGame = async()=>{
+        const {roomId: s, userId: c, avatarId: _, skinId: b, role: k, avatarComponents: j, versionId: $, nickname: _e, avatarScale: et, appId: tt, camera: rt, player: it, roomTypeId: nt="", syncToOthers: at, hasAvatar: ot, prioritySync: st, extra: lt={}, removeWhenDisconnected: ut, avatarURL: ct, pathId: ht} = this.network.room.currentNetworkOptions;
+        lt.removeWhenDisconnected = ut;
+        const dt = {
+            id: "start",
+            room_id: s,
+            user_id: c,
+            trace_id: uuid$1(),
+            data: JSON.stringify({
+                avatar_components: JSON.stringify(j),
+                avatar_id: _,
+                skin_id: b,
+                is_host: k ? k == "host" : !0,
+                skin_data_version: b !== void 0 && $ !== void 0 ? b + $ : void 0,
+                nick_name: encodeURIComponent(_e || ""),
+                app_id: tt,
+                camera: rt,
+                player: it,
+                pathId: ht,
+                room_type_id: nt,
+                syncToOthers: at,
+                hasAvatar: ot,
+                avatarSize: et,
+                prioritySync: st,
+                avatarURL: ct,
+                extra: JSON.stringify(lt)
+            })
+        };
+        this.send(dt);
+        const ft = JSON.parse(dt.data);
+        delete ft.token,
+        logger.infoAndReportMeasurement({
+            metric: "startGame",
+            extra: ft,
+            startTime: Date.now()
+        })
+    };
+    this.network = s,
+    this.heartbeat = new Heartbeat({
+        ping: c=>{
+            var _;
+            if (!this.connected) {
+                this.heartbeat.stop(),
+                (_ = s.room.stats) == null || _.assign({
+                    rtt: 0
+                });
+                return
+            }
+            this.send({
+                id: "heartbeat",
+                data: c
+            })
+        }
+        ,
+        pong(c) {
+            var _;
+            (_ = s.room.stats) == null || _.assign({
+                rtt: c
+            })
+        }
+    })
   }
-
   get connection() {
-    return this._ws;
+      return this._ws
   }
   start() {
     this._hasTimeout = !1;
-    const e = this.getAddress();
-    logger.info(`connecting to ${e}`);
-    const t = Date.now();
-    (this._ws = new WebSocket(e)),
-      (this._openTimer = new Timeout(() => {
-        const r = `Failed to open websocket in ${DEFAULT_OPEN_TIMEOUT_MS} ms`;
-        (this._hasTimeout = !0),
-          this.emit("socketClosed", new InitNetworkTimeoutError(r));
-      }, DEFAULT_OPEN_TIMEOUT_MS)),
-      (this._ws.onopen = () => {
-        var r;
-        (r = this._openTimer) == null || r.clear(),
-          (this.connected = !0),
-          this.heartbeat.start(),
-          this.network.room.currentNetworkOptions.reconnect ||
-            (logger.infoAndReportMeasurement({
-              type: "wsOpenedAt",
-              group: "joinRoom"
-            }),
-            logger.infoAndReportMeasurement({
-              type: "wsOpenedCost",
-              group: "joinRoom"
-            }));
-      }),
-      this.handleWSEvent();
+    const s = this.getAddress();
+    logger.info(`connecting to ${s}`);
+    const c = Date.now();
+    this._ws = new WebSocket(s),
+    this._openTimer = new Timeout(()=>{
+        const _ = `Failed to open websocket in ${DEFAULT_OPEN_TIMEOUT_MS} ms`;
+        this._hasTimeout = !0,
+        this.emit("socketClosed", new InitNetworkTimeoutError(_))
+    }
+    ,DEFAULT_OPEN_TIMEOUT_MS),
+    this._ws.onopen = ()=>{
+        var _;
+        (_ = this._openTimer) == null || _.clear(),
+        this.connected = !0,
+        this.heartbeat.start(),
+        this.network.room.currentNetworkOptions.reconnect || (logger.infoAndReportMeasurement({
+            metric: "wsOpenedAt",
+            group: "joinRoom",
+            startTime: this.network.room._startTime
+        }),
+        logger.infoAndReportMeasurement({
+            metric: "wsOpenedCost",
+            group: "joinRoom",
+            startTime: c
+        }))
+    }
+    ,
+    this.handleWSEvent()
   }
   getAddress() {
-    const {
-        wsServerUrl: e,
-        reconnect: t,
-        sessionId: r,
-        token: n,
-        roomId: o,
-        userId: a,
-        pageSession: s,
-      } = this.network.room.currentNetworkOptions,
-      l = this.network.room.skinId;
-    let u = e;
-    t && (u = u + `?reconnect=true&lastSessionID=${r}`);
-    const c =
-      `userId=${a}&roomId=${o}&pageSession=${s}` +
-      (this.network.room.isHost ? `&skinId=${l}` : "") +
-      (n ? `&token=${n}` : "");
-    return (u = u.indexOf("?") > -1 ? u + "&" + c : u + "?" + c), u;
+    const {wsServerUrl: s, reconnect: c, sessionId: _, token: b, roomId: k, userId: j, pageSession: $} = this.network.room.currentNetworkOptions
+      , _e = this.network.room.skinId;
+    let et = s;
+    c && (et = et + `?reconnect=true&lastSessionID=${_}`);
+    const tt = `userId=${j}&roomId=${k}&pageSession=${$}` + (this.network.room.isHost ? `&skinId=${_e}` : "") + (b ? `&token=${b}` : "");
+    return et = et.indexOf("?") > -1 ? et + "&" + tt : et + "?" + tt,
+    et
   }
   handleWSEvent() {
-    const e = this._ws;
-    e.addEventListener("error", (t) => {
-      (this.connected = !1),
-        logger.error("webscoket error", t),
-        this.emit(
-          "socketClosed",
-          new InternalError(
-            "connect to address error: " +
-              this.network.room.currentNetworkOptions.wsServerUrl
-          )
-        );
-    }),
-      e.addEventListener("close", (t) => {
-        (this.connected = !1), this._onClose(t);
-      }),
-      //接收数据
-      e.addEventListener("message", (t) => {
-        if (!t || this._hasTimeout || !this.connected) return;
-        let r = null;
-        try {
-          r = JSON.parse(t.data);
-          // console.log('接收socket数据:'+t.data)
-        } catch (o) {
-          logger.error(o);
-          return;
-        }
-        if (!r) return;
-        const n = r.id;
-
-        if(n == "heartbeat") console.log("Socket心跳请求时间(ms):", Date.now() - parseInt(r.data))
-
-        if (!!n)
-          switch (
-            (n !== "heartbeat" && logger.info(`receive ws frame: ${t.data}`), n)
-          ) {
-            case "fail":
-              break;
-            case "init":
-              try {
-                const o = r.data.slice(-37, -1);
-                reporter.updateBody({
-                  serverSession: o,
-                });
-              } catch (o) {
-                console.error(o);
-              }
-              this.network.rtcp.start();
-              break;
-            case "heartbeat":
-              this.heartbeat.pong(r.data);
-              break;
-            case "offer":
-              this.network.rtcp.setRemoteDescription(
-                r.data,
-                this.network.stream.el
-              );
-              break;
-            case "ice_candidate":
-              this.network.rtcp.addCandidate(r.data);
-              break;
-            case "start":
-              console.log("server start", JSON.stringify(r));
-              this.emit("gameRoomAvailable", r);
-              break;
-            case "error":
-              try {
-                const { Code: o, Msg: a } = JSON.parse(r.data);
-                if (o) {
-                  if (o == 3003)
-                    return this.emit("socketClosed", new TokenExpiredError());
-                  if (authenticationErrorCodes.indexOf(o) > -1)
-                    return this.emit(
-                      "socketClosed",
-                      new AuthenticationError("\u9274\u6743\u9519\u8BEF:" + a)      //鉴权错误
-                    );
+      const s = this._ws;
+      s.addEventListener("error", c=>{
+          this.connected = !1,
+          logger.error("webscoket error", c),
+          this.emit("socketClosed", new InternalError("connect to address error: " + this.network.room.currentNetworkOptions.wsServerUrl))
+      }
+      ),
+      s.addEventListener("close", c=>{
+          this.connected = !1,
+          this._onClose(c)
+      }
+      ),
+      s.addEventListener("message", c=>{
+          var k;
+          if (!c || this._hasTimeout || !this.connected)
+              return;
+          let _ = null;
+          try {
+              _ = JSON.parse(c.data)
+          } catch (j) {
+              logger.error(j);
+              return
+          }
+          if (!_)
+              return;
+          const b = _.id;
+          if (!!b)
+              switch (b !== "heartbeat" && logger.info(`receive ws frame: ${c.data}`),
+              b) {
+              case "fail":
+                  break;
+              case "init":
+                  try {
+                      const j = (k = JSON.parse(_.data)) == null ? void 0 : k.session_id;
+                      reporter.updateBody({
+                          serverSession: j
+                      }),
+                      tracker.updateHeader({
+                          serverSession: j
+                      })
+                  } catch {
+                      const $ = _.data.slice(-37, -1);
+                      reporter.updateBody({
+                          serverSession: $
+                      }),
+                      tracker.updateHeader({
+                          serverSession: $
+                      })
+                  }
+                  this.network.rtcp.start();
+                  break;
+              case "heartbeat":
+                  this.heartbeat.pong(_.data);
+                  break;
+              case "offer":
+                  this.network.rtcp.setRemoteDescription(_.data);
+                  break;
+              case "answer":
+                  this.network.rtcp.onNegotiationAnswer(_.data);
+                  break;
+              case "ice_candidate":
+                  this.network.rtcp.addCandidate(_.data);
+                  break;
+              case "start":
                   {
-                    const s = util.getErrorByCode(o);
-                    this.emit("socketClosed", new s(a));
+                      const {room_id: j, data: $, session_id: _e} = _ || {};
+                      let et = null;
+                      (!j || !$ || !_e) && (et = new AbnormalDataStructureError("startGame responseData error:" + _));
+                      try {
+                          JSON.parse($)
+                      } catch {
+                          et = new AbnormalDataStructureError("startGame responseData error:" + _)
+                      }
+                      if (et)
+                          return this.emit("socketClosed", et);
+                      this.emit("gameRoomAvailable", _)
                   }
-                }
-              } catch (d) {
-                const _ = new InternalError(
-                  "JSON.parse websocket data error: " + r.data
-                );
-                logger.error(d, _);
-                this.emit("socketClosed", _);
+                  break;
+              case "error":
+                  try {
+                      const {Code: j, Msg: $} = JSON.parse(_.data);
+                      if (j) {
+                          if (j == 3003)
+                              return this.emit("socketClosed", new TokenExpiredError);
+                          if (authenticationErrorCodes.indexOf(j) > -1)
+                              return this.emit("socketClosed", new AuthenticationError("\u9274\u6743\u9519\u8BEF:" + $));
+                          {
+                              const _e = getErrorByCode(j);
+                              this.emit("socketClosed", new _e($))
+                          }
+                      }
+                  } catch (j) {
+                      const $ = new InternalError("JSON.parse websocket data error: " + _.data);
+                      logger.error(j, $),
+                      this.emit("socketClosed", $)
+                  }
+                  break;
+              case "checkLatency":
+                  {
+                      const j = _.packet_id
+                        , $ = _.data.split(",");
+                      this.onLatencyCheck({
+                          packetId: j,
+                          addresses: $
+                      });
+                      break
+                  }
+              default:
+                  logger.warn("unkown ws message type", b, _)
               }
-              break;
-            case "checkLatency": {
-              const o = r.packet_id,
-                a = r.data.split(",");
-              this.onLatencyCheck({
-                packetId: o,
-                addresses: a,
-              });
-              break;
-            }
-            default:
-              logger.warn("unkown ws message type", n, r);
-          }
-      });
+      }
+      )
   }
-  onLatencyCheck(e) {
-    const t = [...new Set(e.addresses || [])];
-    Promise.all(
-      t.map((r) => ({
-        [r]: 9999,
-      }))
-    ).then((r) => {
-      const n = Object.assign({}, ...r);
-      this.latency(n, e.packetId);
-    });
+  onLatencyCheck(s) {
+      const c = [...new Set(s.addresses || [])];
+      Promise.all(c.map(_=>({
+          [_]: 9999
+      }))).then(_=>{
+          const b = Object.assign({}, ..._);
+          this.latency(b, s.packetId)
+      }
+      )
   }
   wsNoReady() {
-    return (
-      this._ws.readyState == WebSocket.CLOSED ||
-      this._ws.readyState == WebSocket.CLOSING ||
-      this._ws.readyState == WebSocket.CONNECTING
-    );
+      return this._ws.readyState == WebSocket.CLOSED || this._ws.readyState == WebSocket.CLOSING || this._ws.readyState == WebSocket.CONNECTING
   }
   prepareReconnect() {
-    this._close({
-      code: WS_CLOSE_RECONNECT,
-      reason: "reconnect",
-    });
+      this._close({
+          code: WS_CLOSE_RECONNECT,
+          reason: "reconnect"
+      })
   }
-  _onClose({ code: e, reason: t }) {
-    this._openTimer && this._openTimer.clear(),
-      logger.warn(`ws closed: ${e} ` + t),
-      [WS_CLOSE_RECONNECT, WS_CLOSE_NORMAL].includes(e) ||
-        this.emit("socketClosed", new InternalError("Websocket error"));
+  _onClose({code: s, reason: c}) {
+      this._openTimer && this._openTimer.clear(),
+      logger.warn(`ws closed: ${s} ` + c),
+      [WS_CLOSE_RECONNECT, WS_CLOSE_NORMAL].includes(s) || this.emit("socketClosed", new InternalError("Websocket error"))
   }
-  _close({ code: e, reason: t }) {
-    var r;
-    (r = this._ws) == null || r.close(e, t);
+  _close({code: s, reason: c}) {
+      var _;
+      (_ = this._ws) == null || _.close(s, c)
   }
   quit() {
-    this._close({
-      code: WS_CLOSE_NORMAL,
-      reason: "quit",
-    });
+      this._close({
+          code: WS_CLOSE_NORMAL,
+          reason: "quit"
+      })
   }
 }

+ 45 - 64
src/StaticMeshEvent.js

@@ -1,87 +1,68 @@
 
 import EMeshType from "./enum/EMeshType.js"
+import PointerEventTypes from "./enum/PointerEventTypes.js"
 
-const LongPressMesh = [EMeshType.XAvatar];
 export default class StaticMeshEvent extends EventEmitter {
-    constructor(e) {
+    constructor(s) {
         super();
-        E(this, "scene");
-        E(this, "_staringPointerTime", -1);
-        E(this, "_pickedMeshID", "0");
-        E(this, "_pointerDownTime", -1);
-        E(this, "_currentPickPoint");
-        E(this, "_longPressDelay", 500);
-        E(this, "_pointerTapDelay", 200);
-        E(this, "_pickedMeshType");
-        E(this, "registerEvent", ()=>{
-            this.scene.onPrePointerObservable.add(this.onDown, BABYLON.PointerEventTypes.POINTERDOWN),
-            this.scene.onPrePointerObservable.add(this.onUp, BABYLON.PointerEventTypes.POINTERUP),
-            this.scene.onPrePointerObservable.add(this.onDoubleTap, BABYLON.PointerEventTypes.POINTERDOUBLETAP),
+        this._staringPointerTime = -1;
+        this._pickedMeshID = "0";
+        this._pointerDownTime = -1;
+        this._currentPickPoint = null;
+        this._longPressDelay = 500;
+        this._pointerTapDelay = 200;
+        this._pickedMeshType = null;
+        this.registerEvent = ()=>{
+            this.scene.onPrePointerObservable.add(this.onDown, PointerEventTypes.POINTERDOWN),
+            this.scene.onPrePointerObservable.add(this.onUp, PointerEventTypes.POINTERUP),
+            this.scene.onPrePointerObservable.add(this.onDoubleTap, PointerEventTypes.POINTERDOUBLETAP),
             this.scene.onDispose = ()=>{
                 this.scene.onPrePointerObservable.removeCallback(this.onUp),
                 this.scene.onPrePointerObservable.removeCallback(this.onDown),
                 this.scene.onPrePointerObservable.removeCallback(this.onDoubleTap)
             }
         }
-        );
-        E(this, "onUp", ()=>{
+        this.onUp = ()=>{
             if (Date.now() - this._pointerDownTime < this._pointerTapDelay && !this.scene._inputManager._isPointerSwiping()) {
-                this.scene._inputManager._totalPointersPressed = 0;
-                let e = this._currentPickPoint;
-                e != null && LongPressMesh.indexOf(e.type) == -1 && this.scene._inputManager._totalPointersPressed == 0 && this.emit("pointTap", e),
-                e != null && LongPressMesh.indexOf(e.type) != -1 && (e = this.onPointerTap(t=>t.isPickable && LongPressMesh.indexOf(t.xtype) == -1),
-                e != null && this.emit("pointTap", e))
+                const s = this._currentPickPoint;
+                s != null && this.emit("pointTap", s)
             }
         }
-        );
-        E(this, "onDown", ()=>{
-            let e = this.onPointerTap(t=>t.isPickable);
-            this._currentPickPoint = e,
-            this._pointerDownTime = Date.now(),
-            e != null && LongPressMesh.indexOf(e.type) != -1 && (this._staringPointerTime = Date.now(),
-            this._pickedMeshID = e.id,
-            this._pickedMeshType = e.type,
-            window.setTimeout(()=>{
-                e = this.onPointerTap(t=>t.isPickable && t.xtype == this._pickedMeshType && t.xid == this._pickedMeshID),
-                e !== null && Date.now() - this._staringPointerTime > this._longPressDelay && !this.scene._inputManager._isPointerSwiping() && this.scene._inputManager._totalPointersPressed !== 0 && (this._staringPointerTime = 0,
-                this.emit("longPress", e))
-            }
-            , this._longPressDelay))
+        this.onDown = ()=>{
+            const s = this.onPointerTap(c=>c.isPickable);
+            this._currentPickPoint = s,
+            this._pointerDownTime = Date.now()
         }
-        );
-        E(this, "onDoubleTap", ()=>{
-            const e = this.onPointerTap(void 0);
-            e != null && this.emit("pointDoubleTap", e)
+        this.onDoubleTap = ()=>{
+            const s = this.onPointerTap(void 0);
+            s != null && this.emit("pointDoubleTap", s)
         }
-        );
-        this.manager = e,
-        this.scene = e.Scene,
-        this.registerEvent(),
-        this._currentPickPoint = null,
-        this._pickedMeshType = null
+        this.manager = s,
+        this.scene = s.Scene,
+        this.registerEvent();
     }
-    onPointerTap(e, t=!1) {
-        var n, o;
-        let r = new BABYLON.PickingInfo;
-        if (t) {
-            const a = this.scene.multiPick(this.scene.pointerX, this.scene.pointerY, e, void 0, void 0);
-            a && a.length > 1 ? r = a[1] : a && (r = a[0])
+    onPointerTap(s, c=!1) {
+        var b, k;
+        let _ = new PickingInfo;
+        if (c) {
+            const j = this.scene.multiPick(this.scene.pointerX, this.scene.pointerY, s, void 0, void 0);
+            j && j.length > 1 ? _ = j[1] : j && (_ = j[0])
         } else
-            r = this.scene.pick(this.scene.pointerX, this.scene.pointerY, e, !1, null);
-        if (r.hit) {
-            const a = (n = r == null ? void 0 : r.pickedPoint) == null ? void 0 : n.asArray();
-            if (a) {
-                const [s,l,u] = a
-                  , c = xversePosition2Ue4({
-                    x: s,
-                    y: l,
-                    z: u
+            _ = this.scene.pick(this.scene.pointerX, this.scene.pointerY, s, !1, null);
+        if (_.hit) {
+            const j = (b = _ == null ? void 0 : _.pickedPoint) == null ? void 0 : b.asArray();
+            if (j) {
+                const [$,_e,et] = j
+                  , tt = xversePosition2Ue4({
+                    x: $,
+                    y: _e,
+                    z: et
                 });
                 return {
-                    name: (o = r.pickedMesh) == null ? void 0 : o.name,
-                    type: r.pickedMesh.xtype,
-                    id: r.pickedMesh.xid,
-                    point: c
+                    name: (k = _.pickedMesh) == null ? void 0 : k.name,
+                    type: _.pickedMesh.xtype,
+                    id: _.pickedMesh.xid,
+                    point: tt
                 }
             }
         }

Diferenças do arquivo suprimidas por serem muito extensas
+ 535 - 338
src/Stats.js


+ 31 - 38
src/Stream.js

@@ -1,53 +1,46 @@
 import InternalError from "./error/InternalError.js"
 import Logger from "./Logger.js"
 
-const logger = new Logger('stream')
 export default class Stream {
-    constructor(e) {
-        this.el = null
-        this._streamPlayTimer = null
-        if (!e) {
-            this.el = this.createVideoElement();
-            return
-        }
-        this.el = e
-    }
-
-    play(){
-        return new Promise((e,t)=>{
-            this._streamPlayTimer = new Timeout(()=>{
-                t(new InternalError("Stream play timeout"))
+    constructor(o) {
+        if (this._streamPlayTimer = null,
+        this.play = ()=>new Promise((s,c)=>{
+            this._streamPlayTimer = new Timeout$1(()=>{
+                c("Stream play timeout")
             }
             ,5e3),
             this.el && this.el.play().then(()=>{
-                var r;
-                e(),
-                logger.info("Media can autoplay"),
-                (r = this._streamPlayTimer) == null || r.clear()
+                var _;
+                s(),
+                (_ = this._streamPlayTimer) == null || _.clear()
             }
-            ).catch(r=>{
-                var n;
-                logger.error("Media Failed to autoplay"),
-                logger.error(r),
-                t(new InternalError("Media Failed to autoplay")),
-                (n = this._streamPlayTimer) == null || n.clear()
+            ).catch(_=>{
+                var b;
+                c("Media Failed to autoplay"),
+                (b = this._streamPlayTimer) == null || b.clear()
             }
             )
         }
-        )
+        ),
+        !o) {
+            this.el = this.createVideoElement();
+            return
+        }
+        this.el = o
     }
-
     createVideoElement() {
-        const e = document.createElement("video");
-        return e.muted = !0,
-        e.autoplay = !1,
-        e.playsInline = !0,
-        e.setAttribute("autostart", "false"),
-        e.setAttribute("controls", "controls"),
-        e.setAttribute("muted", "true"),
-        e.setAttribute("preload", "auto"),
-        e.setAttribute("hidden", "hidden"),
-        document.body.appendChild(e),
-        e
+        const o = document.createElement("video");
+        return o.muted = !0,
+        o.autoplay = !1,
+        o.playsInline = !0,
+        o.width = 360,
+        o.height = 640,
+        o.setAttribute("autostart", "false"),
+        o.setAttribute("controls", "controls"),
+        o.setAttribute("muted", "true"),
+        o.setAttribute("preload", "auto"),
+        o.setAttribute("hidden", "hidden"),
+        document.body.appendChild(o),
+        o
     }
 }

+ 112 - 44
src/TV.js

@@ -1,18 +1,42 @@
 import XDecalManager from "./XDecalManager.js"
 import XTelevision from "./XTelevision.js";
+import Logger from "./Logger.js"
+import InternalError from "./error/InternalError.js"
+
+const logger = new Logger("tv");
 
 export default class TV extends XTelevision {
-    constructor(id, meshUrl, room, options) {
-        super(room.scene, meshUrl, room.sceneManager, options);
-        E(this, "decal");
-        E(this, "id");
-        E(this, "imageUrl");
-        E(this, "mode", "video");
-        E(this, "room");
-        E(this, "setVideo", (e, t=!1, r=!0)=>super.setVideo(e, t, r).then(()=>this));
-        this.id = id,
-        this.room = room,
-        this.decal = new XDecalManager(room.sceneManager)
+    constructor(s, c, _, b) {
+        super(_.scene, c, _.sceneManager, b);
+        this.imageUrl = null;
+        this.mode = 'video';
+        this._isStoped = !1;
+        this.setVideo = (s,c=!1,_=!0)=>(logger.warn("setVideo", {
+            isLive: c,
+            fixElement: _,
+            src: s.src
+        }),
+        super.setVideo(s, c, _).then(()=>(this._isStoped = !1,
+        logger.warn("setVideo Success", {
+            isLive: c,
+            fixElement: _,
+            src: s.src
+        }),
+        this)));
+
+        this.id = s,
+        this.room = _,
+        this.decal = new XDecalManager(_.sceneManager)
+    }
+    get isStoped() {
+        return this._isStoped
+    }
+    get objectFit() {
+        return this.tvFitMode
+    }
+    set objectFit(s) {
+        this.objectFit !== s && (this.tvFitMode = s,
+        this.getVideoMat() && this.changeTvFitMode())
     }
     show() {
         this.mode === "video" ? this.toggle(!0) : this.mode === "poster" && this.showPoster()
@@ -28,62 +52,106 @@ export default class TV extends XTelevision {
         this.toggle(!1)
     }
     showPoster() {
-        const e = this.imageUrl;
-        if (!e)
+        const s = this.imageUrl;
+        if (!s)
             return Promise.reject("set poster url before show it");
         if (!this.decal)
             return Promise.reject("decal was not found");
-        const t = this.id;
+        const c = this.id;
         return this.decal.addDecal({
-            id: t,
+            id: c,
             meshPath: this.meshPath
         }).then(()=>{
-            var r;
+            var _;
             this.mode = "poster",
-            (r = this.decal) == null || r.setDecalTexture({
-                id: t,
-                buffer: e
+            (_ = this.decal) == null || _.setDecalTexture({
+                id: c,
+                buffer: s
             }).then(()=>{
-                var n;
-                (n = this.decal) == null || n.toggle(t, !0)
+                var b;
+                (b = this.decal) == null || b.toggle(c, !0)
             }
             )
         }
         )
     }
-    setPoster(e) {
-        return this.imageUrl = e,
+    setPoster(s) {
+        return this.imageUrl = s,
         this.showPoster()
     }
     hidePoster() {
         return this.decal ? this.decal.toggle(this.id, !1) : Promise.reject("decal was not found")
     }
-    setUrl(e) {
-        const {url: t, loop: r, muted: n} = e || {};
-        return t ? super.setUrl({
-            url: t,
-            bLoop: r,
-            bMuted: n
-        }).then(()=>(
-            this.videoElement && (
-                this.videoElement.crossOrigin = "anonymous",
-                this.videoElement.playsInline = !0,
-                this.videoElement.load()
-            ),
-            this.mode = "video",
-            this
-        )) : Promise.reject("tv url is required")
-    }
-    mirrorFrom(e) {
-        const t = e.getVideoMat();
-        return this.setSameVideo(t).then(()=>{
+    async setUrl(s) {
+        const c = Date.now()
+          , {url: _, loop: b=!1, muted: k} = s || {};
+        if (logger.warn("setUrl", {
+            url: _,
+            loop: b,
+            muted: k
+        }),
+        !_)
+            return logger.error("tv url is required"),
+            Promise.reject("tv url is required");
+        await super.setUrl({
+            url: _,
+            bLoop: b,
+            bMuted: k
+        });
+        const j = this.videoElement;
+        if (!j)
+            return Promise.reject(new InternalError("video element is not found"));
+        j.crossOrigin = "anonymous",
+        j.playsInline = !0,
+        j.load(),
+        this.mode = "video",
+        this._isStoped = !1;
+        try {
+            await new Promise($=>{
+                j.oncanplay = ()=>{
+                    logger.warn(`setUrl success, video oncanplay within ${(Date.now() - c) / 1e3}s`, {
+                        url: _,
+                        loop: b,
+                        muted: k
+                    }),
+                    this.room.afterSetUrlHook(),
+                    j.play(),
+                    $(this)
+                }
+            }
+            )._timeout(15e3, new InternalError("video oncanplay timeout in 15s"))
+        } catch ($) {
+            return logger.error($),
+            Promise.reject($)
+        }
+        return this
+    }
+    stop() {
+        return logger.warn("tv stop success"),
+        this._isStoped = !0,
+        this.room.afterTvStopedHook(),
+        super.stop()
+    }
+    play() {
+        return this._isStoped = !1,
+        this.room.afterTvPlayedHook(),
+        super.play().then(()=>{
+            logger.warn("tv play success"),
+            !this.videoElement && logger.error("tv play fake success, videoElement is not found")
+        }
+        ).catch(s=>(logger.error("tv play error", s),
+        Promise.reject(s)))
+    }
+    mirrorFrom(s) {
+        const c = s.getVideoMat();
+        return this.setSameVideo(c).then(()=>{
             this.toggle(!0)
         }
         )
     }
     clean() {
-        var e;
+        var s;
         this.cleanTv(!1, !0),
-        (e = this.decal) == null || e.deleteDecal(this.id)
+        (s = this.decal) == null || s.deleteDecal(this.id)
     }
 }

+ 8 - 9
src/Timeout.js

@@ -1,9 +1,8 @@
 export default class Timeout {
-    constructor(e, t, r=!0) {
-        this._timeout = null
-        this._fn = e,
-        this._delay = t,
-        r && this.start()
+    constructor(o, s, c=!0) {
+        this._fn = o,
+        this._delay = s,
+        c && this.start()
     }
     get delay() {
         return this._delay
@@ -11,14 +10,14 @@ export default class Timeout {
     get isSet() {
         return !!this._timeout
     }
-    setDelay(e) {
-        this._delay = e
+    setDelay(o) {
+        this._delay = o
     }
     start() {
         this.isSet || (this._timeout = window.setTimeout(()=>{
-            const e = this._fn;
+            const o = this._fn;
             this.clear(),
-            e()
+            o()
         }
         , this._delay))
     }

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 1575
src/Workers-bk.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 1234 - 1389
src/Workers.js


+ 240 - 225
src/XAnimationController.js

@@ -1,14 +1,15 @@
 import {avatarLoader} from "./XAvatarLoader.js"
 import AvatarAnimationError from "./error/AvatarAnimationError.js"
 import Logger from "./Logger.js"
+import EMotionType from "./enum/EMotionType.js"
 
 const logger = new Logger('AnimationController')
 export default class XAnimationController {
-    constructor(avatar) {
+    constructor(o) {
         this.iBodyAnim = void 0,
         this.animations = [],
         this.defaultAnimation = "Idle",
-        this.onPlay = "Idle",
+        this.onPlay = void 0,
         this.loop = !0,
         this.animationExtras = [],
         this.enableBlend = !1,
@@ -17,283 +18,297 @@ export default class XAnimationController {
         this._lodMask = new Map,
         this.activeFaceAnimation = void 0,
         this.iFaceAnim = void 0,
-        this.onPlayObservable = new Observable,
-
-        this._avatar = avatar,
-        this._scene = avatar.avatarManager.scene,
+        this.onPlayObservable = new BABYLON.Observable,
+        this.stateObserver = void 0,
+        this.speed = 0,
+        this.moveThresh = .001,
+        this.motionMap = new Map,
+        this.playAnimation = (s,c,_=0,b,k,j)=>new Promise(($,_e)=>{
+            const et = this.motionMap.get(s);
+            if (et && (s = et),
+            this._isPlaying(s, _))
+                return $(null);
+            if (GEngine.engineOption.bDisableSkeletonAnim)
+                return setTimeout(()=>{
+                    this.onPlayObservable.notifyObservers(this._scene)
+                }
+                , 10),
+                this.detachAnimation(_),
+                $(null);
+            if (this._registerAnimInfo(s, c, _, b, k, j),
+            !this._isAnimate())
+                return $(null);
+            this._prerocess(s, c),
+            this._avatar.avatarManager.loadAnimation(s).then(tt=>{
+                if (!tt)
+                    return _e(new AvatarAnimationError("animation group does not exist"));
+                if (!this._avatar.skeleton)
+                    return $(null);
+                const rt = this._mappingSkeleton(tt);
+                if (!rt)
+                    return _e(new AvatarAnimationError(`mapping animation failed: when ${s} attach to ${this._avatar.avatarType}`));
+                if (rt && this._isAnimationValid(rt))
+                    return rt.dispose(),
+                    _e();
+                if (this.enableSkLod && this.skeletonMask(rt, _),
+                this.detachAnimation(_),
+                _ == 0 ? this.iBodyAnim.animGroup = rt : _ == 1 && (this.iFaceAnim.animGroup = rt),
+                !this._playAnimation(_))
+                    return _e(new AvatarAnimationError("[Engine] play animation failed, animtion resource does not match current character"));
+                this.postObserver = rt.onAnimationEndObservable.addOnce(()=>(this._postprocess(_),
+                $(null)))
+            }
+            ).catch(tt=>{
+                _e(tt)
+            }
+            )
+        }
+        ),
+        this.stopAnimation = (s=0)=>{
+            var c, _, b, k;
+            switch (s) {
+            case 0:
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((c = this.iBodyAnim) == null || c.animGroup.stop());
+                break;
+            case 1:
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((_ = this.iFaceAnim) == null || _.animGroup.stop());
+                break;
+            case 2:
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((b = this.iBodyAnim) == null || b.animGroup.stop()),
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((k = this.iFaceAnim) == null || k.animGroup.stop());
+                break
+            }
+        }
+        ,
+        this.pauseAnimation = (s=0)=>{
+            var c, _, b, k;
+            switch (s) {
+            case 0:
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((c = this.iBodyAnim) == null || c.animGroup.pause());
+                break;
+            case 1:
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((_ = this.iFaceAnim) == null || _.animGroup.pause());
+                break;
+            case 2:
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((b = this.iBodyAnim) == null || b.animGroup.pause()),
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((k = this.iFaceAnim) == null || k.animGroup.pause());
+                break
+            }
+        }
+        ,
+        this.resetAnimation = (s=0)=>{
+            var c, _, b, k;
+            switch (s) {
+            case 0:
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((c = this.iBodyAnim) == null || c.animGroup.reset());
+                break;
+            case 1:
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((_ = this.iFaceAnim) == null || _.animGroup.reset());
+                break;
+            case 2:
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((b = this.iBodyAnim) == null || b.animGroup.reset()),
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((k = this.iFaceAnim) == null || k.animGroup.reset());
+                break
+            }
+        }
+        ,
+        this._avatar = o,
+        this._scene = o.avatarManager.scene,
         this.animationExtras.push(action.Cheering.animName),
         this._boneMap = new Map
     }
-    
-    // aniType :0 身体动画 :1 脸部动画
-    playAnimation = (animationName, isLoop, aniType=0, c, d, _)=>new Promise((resolve, reject)=>{
-        // zeg 传入i为任意动画名即可播放该动画,比如"GiftClap"
-        // window.room.avatarManager.avatars.get(window.room.userId).playAnimation({"animationName": "GiftClap", "loop":true})
-        if (
-            this._isPlaying(animationName, aniType) || 
-            (this._registerAnimInfo(animationName, isLoop, aniType, c, d, _), !this._isAnimate())
-        ) 
-        return resolve(null);
-
-        this._prerocess(animationName, isLoop),
-        this._avatar.avatarManager.loadAnimation(this._avatar.avatarType, animationName).then(skeleton => {
-            if (!skeleton) return reject(new AvatarAnimationError("animation group does not exist"));
-
-            // skeleton是AnimationGroup类型
-            skeleton = this._mappingSkeleton(skeleton);
-            if (!skeleton) return reject(new AvatarAnimationError("mapping animation failed"))
-            
-            if (skeleton && this._isAnimationValid(skeleton))
-                return skeleton.dispose(),
-                reject(new AvatarAnimationError("mapping animation failed"));
-
-            this.enableSkLod && this.skeletonMask(skeleton, aniType)
-            this.detachAnimation(aniType)   // 停止当前动画
-            aniType == 0 && (this.iBodyAnim.animGroup = skeleton) 
-            aniType == 1 && (this.iFaceAnim.animGroup = skeleton)
-
-            if (!this._playAnimation(aniType)) return reject(
-                new AvatarAnimationError("[Engine] play animation failed, animtion resource does not match current character"));
-            
-            this._playEffect(),
-            this.postObserver = skeleton.onAnimationEndObservable.addOnce(()=>(
-                this._postprocess(aniType),
-                resolve(null)
-            ))
-        })
-    })
-    
-    stopAnimation = (i=0)=>{
-        var o, s, c, d;
-        switch (i) {
-        case 0:
-            this.iBodyAnim && this.iBodyAnim.animGroup && ((o = this.iBodyAnim) == null || o.animGroup.stop());
-            break;
-        case 1:
-            this.iFaceAnim && this.iFaceAnim.animGroup && ((s = this.iFaceAnim) == null || s.animGroup.stop());
-            break;
-        case 2:
-            this.iBodyAnim && this.iBodyAnim.animGroup && ((c = this.iBodyAnim) == null || c.animGroup.stop()),
-            this.iFaceAnim && this.iFaceAnim.animGroup && ((d = this.iFaceAnim) == null || d.animGroup.stop());
-            break
+    ReceiveTick() {
+        var o;
+        this.stateObserver = (o = this._avatar.avatarManager.sceneManager) == null ? void 0 : o.Scene.onBeforeRenderObservable.add(()=>{
+            this._avatar.movementComponent.enable && this._tickMoveState(this._avatar.movementComponent.currentMotionType)
         }
+        )
     }
-    
-    pauseAnimation = (i=0)=>{
-        var o, s, c, d;
-        switch (i) {
-        case 0:
-            this.iBodyAnim && this.iBodyAnim.animGroup && ((o = this.iBodyAnim) == null || o.animGroup.pause());
-            break;
-        case 1:
-            this.iFaceAnim && this.iFaceAnim.animGroup && ((s = this.iFaceAnim) == null || s.animGroup.pause());
-            break;
-        case 2:
-            this.iBodyAnim && this.iBodyAnim.animGroup && ((c = this.iBodyAnim) == null || c.animGroup.pause()),
-            this.iFaceAnim && this.iFaceAnim.animGroup && ((d = this.iFaceAnim) == null || d.animGroup.pause());
-            break
-        }
+    RemoveTick() {
+        this.stateObserver && this._scene.onBeforeRenderObservable.remove(this.stateObserver)
     }
-
-    resetAnimation = (i=0)=>{
-        var o, s, c, d;
-        switch (i) {
-        case 0:
-            this.iBodyAnim && this.iBodyAnim.animGroup && ((o = this.iBodyAnim) == null || o.animGroup.reset());
+    BindingAnimationId(o, s) {
+        this.motionMap.set(o, s)
+    }
+    _tickMoveState(o) {
+        switch (o) {
+        case EMotionType.Idle:
+            (this.onPlay == this.motionMap.get("Walking") || this.onPlay == this.motionMap.get("Running")) && this.playAnimation(this.motionMap.get("Idle"), !0);
             break;
-        case 1:
-            this.iFaceAnim && this.iFaceAnim.animGroup && ((s = this.iFaceAnim) == null || s.animGroup.reset());
+        case EMotionType.Walk:
+            this.playAnimation(this.motionMap.get("Walking"), !0);
             break;
-        case 2:
-            this.iBodyAnim && this.iBodyAnim.animGroup && ((c = this.iBodyAnim) == null || c.animGroup.reset()),
-            this.iFaceAnim && this.iFaceAnim.animGroup && ((d = this.iFaceAnim) == null || d.animGroup.reset());
+        case EMotionType.Run:
+            this.playAnimation(this.motionMap.get("Running"), !0);
             break
         }
     }
-
-    _isPlaying(e, i) {
-        return i == 0 && this.iBodyAnim != null && this.iBodyAnim.animGroup && e == this.iBodyAnim.name ? !0 : !!(i == 1 && this.iFaceAnim != null && this.iFaceAnim.animGroup && e == this.iFaceAnim.name)
+    _isPlaying(o, s) {
+        return s == 0 && this.iBodyAnim != null && this.iBodyAnim.animGroup && o == this.iBodyAnim.name ? !0 : !!(s == 1 && this.iFaceAnim != null && this.iFaceAnim.animGroup && o == this.iFaceAnim.name)
     }
-    activeAnimation(e=0) {
-        var i, o;
-        switch (e) {
+    activeAnimation(o=0) {
+        var s, c;
+        switch (o) {
         case 0:
-            return (i = this.iBodyAnim) == null ? void 0 : i.animGroup;
+            return (s = this.iBodyAnim) == null ? void 0 : s.animGroup;
         case 1:
-            return (o = this.iFaceAnim) == null ? void 0 : o.animGroup;
+            return (c = this.iFaceAnim) == null ? void 0 : c.animGroup;
         default:
             return
         }
     }
-    enableAnimationBlend(e=.1, i=0) {
-        var o, s, c, d;
-        if (i == 0 && ((o = this.iBodyAnim) == null ? void 0 : o.animGroup))
-            for (const _ of (s = this.iBodyAnim) == null ? void 0 : s.animGroup.targetedAnimations)
-                _.animation.enableBlending = !0,
-                _.animation.blendingSpeed = e;
-        else if (i == 0 && ((c = this.iFaceAnim) == null ? void 0 : c.animGroup))
-            for (const _ of (d = this.iFaceAnim) == null ? void 0 : d.animGroup.targetedAnimations)
-                _.animation.enableBlending = !0,
-                _.animation.blendingSpeed = e
+    enableAnimationBlend(o=.1, s=0) {
+        var c, _, b, k;
+        if (s == 0 && ((c = this.iBodyAnim) == null ? void 0 : c.animGroup))
+            for (const j of (_ = this.iBodyAnim) == null ? void 0 : _.animGroup.targetedAnimations)
+                j.animation.enableBlending = !0,
+                j.animation.blendingSpeed = o;
+        else if (s == 0 && ((b = this.iFaceAnim) == null ? void 0 : b.animGroup))
+            for (const j of (k = this.iFaceAnim) == null ? void 0 : k.animGroup.targetedAnimations)
+                j.animation.enableBlending = !0,
+                j.animation.blendingSpeed = o
     }
-    disableAnimationBlend(e=0) {
-        var i, o, s, c;
-        if (e == 0 && ((i = this.iBodyAnim) == null ? void 0 : i.animGroup))
-            for (const d of (o = this.iBodyAnim) == null ? void 0 : o.animGroup.targetedAnimations)
-                d.animation.enableBlending = !1;
-        else if (e == 0 && ((s = this.iFaceAnim) == null ? void 0 : s.animGroup))
-            for (const d of (c = this.iFaceAnim) == null ? void 0 : c.animGroup.targetedAnimations)
-                d.animation.enableBlending = !1
+    disableAnimationBlend(o=0) {
+        var s, c, _, b;
+        if (o == 0 && ((s = this.iBodyAnim) == null ? void 0 : s.animGroup))
+            for (const k of (c = this.iBodyAnim) == null ? void 0 : c.animGroup.targetedAnimations)
+                k.animation.enableBlending = !1;
+        else if (o == 0 && ((_ = this.iFaceAnim) == null ? void 0 : _.animGroup))
+            for (const k of (b = this.iFaceAnim) == null ? void 0 : b.animGroup.targetedAnimations)
+                k.animation.enableBlending = !1
     }
-    skeletonMask(e, aniType=0) {
-        if (aniType == 0) {
-            const o = this._lodMask.get(this._avatar.distLevel);
-            if (o)
-                for (let s = 0; s < e.targetedAnimations.length; ++s)
-                    o.includes(e.targetedAnimations[s].target.name) || (
-                        e.targetedAnimations.splice(s, 1),
-                        s--
-                    );
+    skeletonMask(o, s=0) {
+        if (s == 0) {
+            const c = this._lodMask.get(this._avatar.distLevel);
+            if (c)
+                for (let _ = 0; _ < o.targetedAnimations.length; ++_)
+                    c.includes(o.targetedAnimations[_].target.name) || (o.targetedAnimations.splice(_, 1),
+                    _--);
             return !0
         }
         return !1
     }
-    detachAnimation(aniType=2) {
-        switch (aniType) {
+    detachAnimation(o=2) {
+        var s, c;
+        switch (o) {
         case 0:
-            // 身体动画
-            this.iBodyAnim && this.iBodyAnim.animGroup && (
-                this.iBodyAnim.animGroup._parentContainer.xReferenceCount && this.iBodyAnim.animGroup._parentContainer.xReferenceCount--,
-                this.iBodyAnim.animGroup.stop(),
-                this.iBodyAnim.animGroup.dispose(),
-                this.iBodyAnim.animGroup = void 0
-            );
+            this.iBodyAnim && this.iBodyAnim.animGroup && (this.iBodyAnim.animGroup._parentContainer && this.iBodyAnim.animGroup._parentContainer.xReferenceCount && this.iBodyAnim.animGroup._parentContainer.xReferenceCount--,
+            this.iBodyAnim.animGroup.stop(),
+            this.iBodyAnim.animGroup.dispose(),
+            this.iBodyAnim.animGroup = void 0);
             break;
         case 1:
-            // 脸部动画
-            this.iFaceAnim && this.iFaceAnim.animGroup && (
-                this.iFaceAnim.animGroup._parentContainer.xReferenceCount && this.iFaceAnim.animGroup._parentContainer.xReferenceCount--,
-                this.iFaceAnim.animGroup.stop(),
-                this.iFaceAnim.animGroup.dispose(),
-                this.iFaceAnim.animGroup = void 0
-            );
+            this.iFaceAnim && this.iFaceAnim.animGroup && (this.iFaceAnim.animGroup._parentContainer && this.iFaceAnim.animGroup._parentContainer.xReferenceCount && this.iFaceAnim.animGroup._parentContainer.xReferenceCount--,
+            this.iFaceAnim.animGroup.stop(),
+            this.iFaceAnim.animGroup.dispose(),
+            this.iFaceAnim.animGroup = void 0);
             break;
         case 2:
-            this.iBodyAnim && this.iBodyAnim.animGroup && (
-                this.iBodyAnim.animGroup._parentContainer.xReferenceCount && this.iBodyAnim.animGroup._parentContainer.xReferenceCount--,
-                this.iBodyAnim.animGroup.stop(),
-                this.iBodyAnim.animGroup.dispose(),
-                this.iBodyAnim.animGroup = void 0
-            ),
-            this.iFaceAnim && this.iFaceAnim.animGroup && (
-                this.iFaceAnim.animGroup._parentContainer.xReferenceCount && this.iFaceAnim.animGroup._parentContainer.xReferenceCount--,
-                this.iFaceAnim.animGroup.stop(),
-                this.iFaceAnim.animGroup.dispose(),
-                this.iFaceAnim.animGroup = void 0
-            );
+            this.iBodyAnim && this.iBodyAnim.animGroup && (this.iBodyAnim.animGroup._parentContainer && this.iBodyAnim.animGroup._parentContainer.xReferenceCount && this.iBodyAnim.animGroup._parentContainer.xReferenceCount--,
+            (s = this.iBodyAnim) == null || s.animGroup.stop(),
+            (c = this.iBodyAnim) == null || c.animGroup.dispose(),
+            this.iBodyAnim.animGroup = void 0),
+            this.iFaceAnim && this.iFaceAnim.animGroup && (this.iFaceAnim.animGroup._parentContainer && this.iFaceAnim.animGroup._parentContainer.xReferenceCount && this.iFaceAnim.animGroup._parentContainer.xReferenceCount--,
+            this.iFaceAnim.animGroup.stop(),
+            this.iFaceAnim.animGroup.dispose(),
+            this.iFaceAnim.animGroup = void 0);
             break
         }
+        this._scene.onDisposeObservable.clear(),
+        this._scene.getEngine().onContextRestoredObservable.clear()
     }
     blendAnimation() {}
-    getAnimation(e, i) {
-        return avatarLoader.animations.get(getAnimationKey(i, e))
-    }
-    _mappingSkeleton(animationGroup) {
-        if (animationGroup) {
-            const animationGroupClone = animationGroup.clone(animationGroup.name, boneOld => {
-                const name = boneOld.name.split(" ").length > 2 ? boneOld.name.split(" ")[2] : boneOld.name;
-                if (this._boneMap.size === (this._avatar.skeleton && this._avatar.skeleton.bones.length)) return this._boneMap.get(name);
+    getAnimation(o, s) {}
+    _mappingSkeleton(o) {
+        if (o) {
+            const s = o.clone(o.name, c=>{
+                var b, k, j;
+                const _ = c.name.split(" ").length > 2 ? c.name.split(" ")[2] : c.name;
+                if (this._boneMap.size === ((b = this._avatar.skeleton) == null ? void 0 : b.bones.length))
+                    return this._boneMap.get(_);
                 {
-                    let bone0 = this._avatar.skeleton && 
-                                this._avatar.skeleton.bones.find(bone => bone.name === boneOld.name || bone.name === boneOld.name.split(" ")[2])
-                    const bone = bone0 && bone0.getTransformNode();
-                    bone && (
-                        bone.name = name,
-                        this._boneMap.set(name, bone)
-                    )
-                    return bone
+                    const $ = (j = (k = this._avatar.skeleton) == null ? void 0 : k.bones.find(_e=>_e.name === c.name || _e.name === c.name.split(" ")[2])) == null ? void 0 : j.getTransformNode();
+                    return $ && ($.name = _,
+                    this._boneMap.set(_, $)),
+                    $
                 }
-            });
-            animationGroupClone._parentContainer = animationGroup._parentContainer
-            return animationGroupClone
+            }
+            );
+            return s._parentContainer = o._parentContainer,
+            s
         } else
             return
     }
-    removeAnimation(e) {
-        const i = avatarLoader.containers.get(e.name);
-        i && (i.dispose(),
-        avatarLoader.containers.delete(e.name),
-        avatarLoader.animations.delete(getAnimationKey(e.name, e.skType)))
+    removeAnimation(o) {
+        const s = avatarLoader.containers.get(o.name);
+        s && (s.dispose(),
+        avatarLoader.containers.delete(o.name))
     }
-    _setPosition(e, i) {
-        this._avatar.priority === 0 && this._avatar.isRender && e === this.defaultAnimation && e != this.onPlay && !this._avatar.isSelected && this._avatar.setPosition(this._avatar.position, !0)
+    _setPosition(o, s) {
+        this._avatar.priority === 0 && this._avatar.isRender && o === this.defaultAnimation && o != this.onPlay && !this._avatar.isSelected && this._avatar.movementComponent.updatePosition(this._avatar.position, !0)
     }
-    _registerAnimInfo(e, i, o=0, s, c, d) {
-        const _ = {
-            name: e,
+    _registerAnimInfo(o, s, c=0, _, b, k) {
+        const j = {
+            name: o,
             skType: this._avatar.avatarType,
-            loop: i,
-            playSpeed: s,
+            loop: s,
+            playSpeed: _,
             currentFrame: 0,
-            startFrame: c,
-            endFrame: d
+            startFrame: b,
+            endFrame: k
         };
-        o == 0 ? this.iBodyAnim == null ? this.iBodyAnim = _ : (this.iBodyAnim.name = e,
+        c == 0 ? this.iBodyAnim == null ? this.iBodyAnim = j : (this.iBodyAnim.name = o,
         this.iBodyAnim.skType = this._avatar.avatarType,
-        this.iBodyAnim.loop = i,
-        this.iBodyAnim.playSpeed = s,
+        this.iBodyAnim.loop = s,
+        this.iBodyAnim.playSpeed = _,
         this.iBodyAnim.currentFrame = 0,
-        this.iBodyAnim.startFrame = c,
-        this.iBodyAnim.endFrame = d) : o == 1 && (this.iFaceAnim == null ? this.iFaceAnim = _ : (this.iFaceAnim.name = e,
+        this.iBodyAnim.startFrame = b,
+        this.iBodyAnim.endFrame = k) : c == 1 && (this.iFaceAnim == null ? this.iFaceAnim = j : (this.iFaceAnim.name = o,
         this.iFaceAnim.skType = this._avatar.avatarType,
-        this.iFaceAnim.loop = i,
-        this.iFaceAnim.playSpeed = s,
+        this.iFaceAnim.loop = s,
+        this.iFaceAnim.playSpeed = _,
         this.iFaceAnim.currentFrame = 0,
-        this.iFaceAnim.startFrame = c,
-        this.iFaceAnim.endFrame = d)),
-        this.onPlay = e,
-        this.loop = i
+        this.iFaceAnim.startFrame = b,
+        this.iFaceAnim.endFrame = k)),
+        this.onPlay = o,
+        this.loop = s
     }
     _isAnimate() {
-        var e;
-        return !(!this._avatar.isRender || !this._avatar.skeleton || ((e = this._avatar.rootNode) == null ? void 0 : e.getChildMeshes().length) == 0)
+        var o;
+        return !(!this._avatar.skeleton || ((o = this._avatar.rootNode) == null ? void 0 : o.getChildMeshes().length) == 0)
     }
-    _prerocess(animationName, isLoop) {
-        this._avatar.isRayCastEnable && this._setPosition(animationName, isLoop),
-        this._avatar.priority === 0 && logger.info(`start play animation: ${animationName} on avatar ${this._avatar.id}`)
+    _prerocess(o, s) {
+        this._avatar.isRayCastEnable && this._setPosition(o, s),
+        this._avatar.priority === 0 && logger.info(`start play animation: ${o} on avatar ${this._avatar.id}`)
     }
-    _playEffect() {
-        this.animationExtras.indexOf(this.iBodyAnim.name) != -1 && action.Cheering.attachPair.forEach(i=>{
-            this._avatar.attachExtraProp(i.obj, i.bone, new Vector3(i.offset.x,i.offset.y,i.offset.z), new Vector3(i.rotate.x,i.rotate.y,i.rotate.z)),
-            this._avatar.showExtra(i.obj)
+    _playAnimation(o=0) {
+        var s, c;
+        if(o == 0 && this.iBodyAnim && ((s = this.iBodyAnim) == null ? void 0 : s.animGroup) ){
+            this.onPlayObservable.notifyObservers(this._scene);
+            this.iBodyAnim.animGroup.start(this.loop, this.iBodyAnim.playSpeed, this.iBodyAnim.startFrame, this.iBodyAnim.endFrame, !1);
+            return !0
         }
-        )
-    }
-    _playAnimation(aniType=0) {
-        if(aniType == 0 && this.iBodyAnim && this.iBodyAnim.animGroup) {
-            // 身体动画
-            this.onPlayObservable.notifyObservers(this._scene)
-            // todo 这里报错
-            try {
-                this.iBodyAnim.animGroup.start(this.loop, this.iBodyAnim.playSpeed, this.iBodyAnim.startFrame, this.iBodyAnim.endFrame, !1)
-            } catch(e) {}
-            return true
-        } else if(aniType == 1 && this.iFaceAnim && this.iFaceAnim.animGroup) {
-            // 脸部动画
-            this.iFaceAnim.animGroup.start(this.loop, this.iFaceAnim.playSpeed, this.iFaceAnim.startFrame, this.iFaceAnim.endFrame, !1)
-            return true
-        } else 
-            return false
+        else{
+            if(o == 1 && this.iFaceAnim && ((c = this.iFaceAnim) == null ? void 0 : c.animGroup)){
+                this.iFaceAnim.animGroup.start(this.loop, this.iFaceAnim.playSpeed, this.iFaceAnim.startFrame, this.iFaceAnim.endFrame, !1);
+                return !0
+            }
+            else{
+                return !1
+            }
+        }
+        // return o == 0 && this.iBodyAnim && ((s = this.iBodyAnim) == null ? void 0 : s.animGroup) ? (this.onPlayObservable.notifyObservers(this._scene),
+        // this.iBodyAnim.animGroup.start(this.loop, this.iBodyAnim.playSpeed, this.iBodyAnim.startFrame, this.iBodyAnim.endFrame, !1),
+        // !0) : o == 1 && this.iFaceAnim && ((c = this.iFaceAnim) == null ? void 0 : c.animGroup) ? (this.iFaceAnim.animGroup.start(this.loop, this.iFaceAnim.playSpeed, this.iFaceAnim.startFrame, this.iFaceAnim.endFrame, !1),
+        // !0) : !1
     }
-    _postprocess(e) {
-        var o, s;
-        let i;
-        e == 0 ? i = (o = this.iBodyAnim) == null ? void 0 : o.name : e == 1 && (i = (s = this.iFaceAnim) == null ? void 0 : s.name),
-        i === action.Cheering.animName && this._avatar.disposeExtra()
+    _postprocess(o) {
+        var s, c;
+        o == 0 ? (s = this.iBodyAnim) == null || s.name : o == 1 && ((c = this.iFaceAnim) == null || c.name)
     }
-    _isAnimationValid(skeleton) {
-        for (let i = 0; i < skeleton.targetedAnimations.length; ++i)
-            if (skeleton.targetedAnimations[i].target)
+    _isAnimationValid(o) {
+        for (let s = 0; s < o.targetedAnimations.length; ++s)
+            if (o.targetedAnimations[s].target)
                 return !1;
         return !0
     }

+ 314 - 351
src/XAvatar.js

@@ -1,522 +1,485 @@
-//const log$E = new Logger$1("Avatar")
-
 import BillboardStatus from "./enum/BillboardStatus.js"
 import {avatarLoader} from "./XAvatarLoader.js"
 import XAnimationController from "./XAnimationController.js"
 import XAvatarComopnent from "./XAvatarComopnent.js"
-import XStateMachine from "./XStateMachine.js"
 import XAvatarBillboardComponent from "./XAvatarBillboardComponent.js"
-
-const castRayOffsetY = .01;
-const castRayTeleportationOffset = 10;
-
-export default class XAvatar {
-    constructor({id, avatarType, priority, avatarManager, assets, status}) {
+import XActor from "./XActor.js"
+import XMovementComponent from "./XMovementComponent.js"
+import Logger from "./Logger.js"
+
+const logger = new Logger('Avatar')
+
+export default class XAvatar extends XActor{
+    constructor({id: o, avatarType: s, priority: c, avatarManager: _, assets: b, status: k}) {
+        var $;
+        super(),
+        this.id = "-1",
+        this.priority = 0,
         this.isRender = !1,
         this.distLevel = 0,
         this.isInLoadingList = !1,
         this.isHide = !1,
         this.isSelected = !1,
         this.pendingLod = !1,
-        this._previousReceivedPosition = new BABYLON.Vector3(0,1e4,0),
+        this.isMoving = !1,
+        this.rootNode = void 0,
         this.distToCam = 1e11,
         this.enableNickname = !0,
         this.distance = 1e11,
         this.isCulling = !1,
         this.reslevel = 0,
         this.isInLoadingQueue = !1,
+        this._scene = void 0,
         this._transparent = 0,
-
-
-        this.id = id,
-        this._avatarManager = avatarManager,
+        this.hide = ()=>(this.isHide = !0,
+        this._hide(),
+        !this.isRender),
+        this._show = ()=>{
+            var _e;
+            this.isHide || (this.setIsPickable(!0),
+            this.bbComponent._attachmentObservers.forEach((et,tt)=>{
+                tt.setEnabled(!0)
+            }
+            ),
+            this.priority == 0 && (this.rootNode.setEnabled(!0),
+            this.isRender = !0,
+            this.avatarManager._updateBillboardStatus(this, BillboardStatus.SHOW),
+            this.component.accessoryMap.forEach(et=>{
+                et.rootComponent.setEnabled(!0)
+            }
+            ),
+            (_e = this.controller) == null || _e.playAnimation(this.controller.onPlay, this.controller.loop)),
+            this.component.accessoryMap.forEach(et=>{
+                et.rootComponent.setEnabled(!0)
+            }
+            ))
+        }
+        ,
+        this.show = ()=>(this.isHide = !1,
+        this._show(),
+        !!this.isRender),
+        this.setAnimations = _e=>{
+            this.controller.animations = _e
+        }
+        ,
+        this.attachToAvatar = (_e,et=!1,tt={
+            x: 0,
+            y: 0,
+            z: 0
+        },rt=!1,it,nt)=>this.bbComponent.attachToAvatar(this, _e, et, tt, rt, nt),
+        this.detachFromAvatar = (_e,et=!1)=>this.bbComponent.detachFromAvatar(this, _e, et),
+        this.getBbox = (_e={})=>this.bbComponent.getBbox(this, _e),
+        this.id = o,
+        this._avatarManager = _,
         this._scene = this.avatarManager.scene,
-        this.clothesList = assets,
-        this._avatarType = avatarType,
-        this.priority = priority || 0,
-        
+        this._avatarType = s,
+        this.priority = c || 0,
         this.controller = new XAnimationController(this),
         this.component = new XAvatarComopnent,
-        this.stateMachine = new XStateMachine(this._scene),
+        this.component.updateAssetList(b);
+        const j = ($ = this.assetList.find(_e=>_e.type === "ANIMATION")) == null ? void 0 : $.id;
+        this.controller.onPlay = this.controller.defaultAnimation = j,
         this.bbComponent = new XAvatarBillboardComponent(this._scene),
-        this.rootNode = new BABYLON.TransformNode(id, this._avatarManager.scene),
-
-        this._avatarScale = status.avatarScale == null ? 1 : status.avatarScale,
-        this._avatarRotation = status.avatarRotation == null ? { pitch: 0, yaw: 0, roll: 0 } : status.avatarRotation,
-        this._avatarPosition = status.avatarPosition == null ? { x: 0, y: 0, z: 0 } : status.avatarPosition,
+        this.rootNode = new BABYLON.TransformNode(o,this._avatarManager.scene),
+        this._avatarScale = k.avatarScale == null ? 1 : k.avatarScale,
+        this._avatarRotation = k.avatarRotation == null ? {
+            pitch: 0,
+            yaw: 0,
+            roll: 0
+        } : k.avatarRotation,
+        this._avatarPosition = k.avatarPosition == null ? {
+            x: 0,
+            y: 0,
+            z: 0
+        } : k.avatarPosition,
         this._isRayCastEnable = avatarSetting.isRayCastEnable,
-        
-        this.setPosition(this._avatarPosition, !0),
+        this.movementComponent = new XMovementComponent(this._avatarManager.sceneManager),
+        this.movementComponent.registerTo(this),
+        this._isRayCastEnable = avatarSetting.isRayCastEnable,
+        this.movementComponent.updatePosition(this._avatarPosition, !0),
         this.setRotation(this._avatarRotation),
         this.setScale(this.scale),
-        this._isRayCastEnable = avatarSetting.isRayCastEnable,
-
-        this._scene.registerBeforeRender(()=>{
+        this._observer = this._scene.onBeforeRenderObservable.add(()=>{
             this.tick()
-        })
-    }
-
-    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()
     }
-
     cullingTick() {
-        this.isCulling && (this.rootNode == null || this.rootNode.getChildMeshes().forEach(i=>{
-            this.distToCam < 50 ? i.visibility = 0 : i.visibility = this._transparent
-        }))
+        var o;
+        this.isCulling && ((o = this.rootNode) == null || o.getChildMeshes().forEach(s=>{
+            this.distToCam < 50 ? s.visibility = 0 : s.visibility = this._transparent
+        }
+        ))
     }
-
-    setTransParentThresh(e) {
-        this._transparent = e
+    setMaterial(o) {
+        var s;
+        (s = this.rootNode) == null || s.getChildMeshes().forEach(c=>{
+            c.material instanceof BABYLON.NodeMaterial && c.material.getInputBlocks().forEach(_=>{
+                _._storedValue instanceof BABYLON.Color3 && (_._storedValue = new BABYLON.Color3)
+            }
+            )
+        }
+        )
+    }
+    get assetList() {
+        return this.component.assetList
+    }
+    setTransParentThresh(o) {
+        this._transparent = o
     }
-
     get isNameVisible() {
         return this.bbComponent.isNameVisible
     }
-
     get isBubbleVisible() {
         return this.bbComponent.isBubbleVisible
     }
-
     get isGiftButtonsVisible() {
         return this.bbComponent.isGiftButtonsVisible
     }
-
     get words() {
         return this.bbComponent.words
     }
-
     get nickName() {
         return this.bbComponent.nickName
     }
-
     get giftButtons() {
         return this.bbComponent.giftButtons
     }
-
     get bubble() {
         return this.bbComponent.bubble
     }
-
     get nameBoard() {
         return this.bbComponent.nameBoard
     }
-
     get avatarManager() {
         return this._avatarManager
     }
-
-    set withinVisibleRange(e) {
-        this.bbComponent.withinVisualRange = e
+    set withinVisibleRange(o) {
+        this.bbComponent.withinVisualRange = o
     }
-
-    setNicknameStatus(e) {
-        return this.bbComponent.setNicknameStatus(e)
+    setNicknameStatus(o) {
+        return this.bbComponent.setNicknameStatus(o)
     }
-
-    setBubbleStatus(e) {
-        return this.bbComponent.setBubbleStatus(e)
+    setBubbleStatus(o) {
+        return this.bbComponent.setBubbleStatus(o)
     }
-
-    setButtonsStatus(e) {
-        return this.bbComponent.setBubbleStatus(e)
+    setButtonsStatus(o) {
+        return this.bbComponent.setButtonsStatus(o)
     }
-
-    setGiftButtonsVisible(e) {
-        return this.bbComponent.setGiftButtonsVisible(e)
+    setGiftButtonsVisible(o) {
+        return this.bbComponent.setGiftButtonsVisible(o)
     }
-
     get avatarType() {
         return this._avatarType
     }
-
-    attachBody(e) {
-        return this.component.addBodyComp(this, e)
+    attachBody(o) {
+        return this.component.addBodyComp(this, o)
     }
-
-    attachDecoration(e) {
-        return this.component.addClothesComp(this, e)
+    attachDecoration(o) {
+        return this.component.addClothesComp(this, o)
     }
-    
-    detachDecoration(e) {
-        return this.component.clearClothesComp(e)
+    detachDecoration(o) {
+        return this.component.clearClothesComp(o)
     }
-
     detachDecorationAll() {
-        return this.component.clearAllClothesComps()
+        return this.component.disposeDress()
     }
-
     get skeleton() {
         return this.component.skeleton
     }
-
     get position() {
         return this._avatarPosition
     }
-
     get rotation() {
         return this._avatarRotation
     }
-
     get scale() {
         return this._avatarScale
     }
-
     _hide_culling() {
         this.bbComponent.updateBillboardStatus(this, BillboardStatus.HIDE),
         this.isCulling = !0
     }
-
     _show_culling() {
-        this.isCulling && (this.rootNode && this.rootNode.getChildMeshes().forEach(e=>{
-            e.visibility = 1
-        }),
+        this.isCulling && (this.rootNode && this.rootNode.getChildMeshes().forEach(o=>{
+            o.visibility = 1
+        }
+        ),
         this.bbComponent.updateBillboardStatus(this, BillboardStatus.SHOW),
         this.isCulling = !1)
     }
-
+    get clothesList() {
+        return this.assetList.filter(o=>o.type != avatarSetting.animations && o.type != avatarSetting.skeleton)
+    }
     _hide() {
         !this.isHide || (this.setIsPickable(!1),
-        this.bbComponent._attachmentObservers.forEach((e,i)=>{
-            i.setEnabled(!1)
+        this.bbComponent._attachmentObservers.forEach((o,s)=>{
+            s.setEnabled(!1)
         }
         ),
         this.priority == 0 ? (this.rootNode.setEnabled(!1),
         this.isRender = !1,
         this.bbComponent.updateBillboardStatus(this, BillboardStatus.HIDE),
-        this.component.accessories.forEach(e=>{
-            e.rootComponent.setEnabled(!1)
+        this.component.accessoryMap.forEach(o=>{
+            o.rootComponent.setEnabled(!1)
         }
         )) : this.isRender && (this.avatarManager.currentLODUsers[this.distLevel]--,
         this.removeAvatarFromScene()),
-        this.component.accessories.forEach(e=>{
-            e.rootComponent.setEnabled(!1)
-        }))
+        this.component.accessoryMap.forEach(o=>{
+            o.rootComponent.setEnabled(!1)
+        }
+        ))
     }
-
-    rotate(e, i, o) {
-        return this.stateMachine.roll(this, e, i, o)
+    rotate(o, s, c) {
+        return this.movementComponent.roll(this, o, s, c)
     }
-
-    set isRayCastEnable(e) {
-        this._isRayCastEnable = e
+    set isRayCastEnable(o) {
+        this._isRayCastEnable = o
     }
-
     get isRayCastEnable() {
         return this._isRayCastEnable
     }
-
     getAvatarId() {
         return this.id
     }
-
     getAvaliableAnimations() {
-        const e = avatarLoader.avaliableAnimation.get(this.avatarType);
-        return e || []
-    }
-
-    // todo i用于控制是否接触地面。目前设默认为true,实时检测模型地面高度
-    setPosition(e, i=!0) {
-        this._avatarPosition = e;
-        if (this.rootNode) {
-            const o = ue4Position2Xverse(this._avatarPosition);
-            let s = !1;
-            if(this.avatarManager.getMainAvatar() ){
-                if(this.id == this.avatarManager.getMainAvatar().id){
-                    Math.abs(o.y - this._previousReceivedPosition.y) > castRayOffsetY && (s = !0);
-                    o.subtract(this._previousReceivedPosition).length() > castRayTeleportationOffset && (s = !0)
-                }
-            }
-            if(this._isRayCastEnable) 
-                if(s || i) {
-                    // 检测模型地面高度
-                    this._castRay(e).then(c=>{
-                        this.rootNode.position = o;
-                        this.rootNode.position.y -= c;
-                    }
-                    ).catch(c=>{
-                        Promise.reject(c)
-                    }) 
-                } else {
-                    // 保持人物高度不变
-                    this.rootNode.position.x = o.x
-                    this.rootNode.position.z = o.z
-                }
-            else this.rootNode.position = o
-            this._previousReceivedPosition = o.clone()
-        }
-        return Promise.resolve(e)
-    }
-
-    setRotation(e) {
-        if (this._avatarRotation = e,
+        const o = avatarLoader.avaliableAnimation.get(this.avatarType);
+        return o || []
+    }
+    setPosition(o) {
+        var c;
+        this._avatarPosition = o;
+        const s = Date.now();
+        return this.rootNode && (this.rootNode.position = ue4Position2Xverse(this._avatarPosition)),
+        (c = this.avatarManager.sceneManager) == null || c.engineRunTimeStats.timeArray_setPosition.add(Date.now() - s),
+        Promise.resolve(o)
+    }
+    setRotation(o) {
+        if (this._avatarRotation = o,
         this.rootNode) {
-            const i = {
-                pitch: e.pitch,
-                yaw: e.yaw + 180,
-                roll: e.roll
+            const s = {
+                pitch: o.pitch,
+                yaw: o.yaw + 180,
+                roll: o.roll
             }
-              , o = ue4Rotation2Xverse(i);
-            this.rootNode.rotation = o
+              , c = ue4Rotation2Xverse(s);
+            this.rootNode.rotation = c
         }
     }
-
-    setAvatarVisible(e) {
-        this.rootNode && (this.rootNode.setEnabled(e),
-        this.rootNode.getChildMeshes().forEach(i=>{
-            i.setEnabled(e)
+    setAvatarVisible(o) {
+        this.rootNode && (this.rootNode.setEnabled(o),
+        this.rootNode.getChildMeshes().forEach(s=>{
+            s.setEnabled(o)
         }
         ))
     }
-
-    setScale(e) {
-        this._avatarScale = e,
-        this.rootNode && (this.rootNode.scaling = new BABYLON.Vector3(e,e,e)),
+    setScale(o) {
+        this._avatarScale = o,
+        this.rootNode && (this.rootNode.scaling = new BABYLON.Vector3(o,o,o)),
         this.bbComponent.bbox && this.getBbox()
     }
-
-    _removeAvatarFromScene() {
-        var e, i;
+    _removeAvatarFromScene(o=!1) {
+        var s, c;
+        this.component.accessoryMap.forEach(_=>{
+            _.detachFrom(!1),
+            _.rootComponent.setEnabled(!1)
+        }
+        ),
         this.isRender = !1,
-        (e = this.controller) == null || e.detachAnimation(),
-        this.component.dispose(this),
-        (i = this.avatarManager.sceneManager) == null || i.lightComponent.removeShadow(this),
-        this.component.accessories.forEach(o=>{
-            o.rootComponent.setEnabled(!1)
-        })
+        this.component.dispose(o),
+        o && ((s = this.controller) == null || s.detachAnimation(),
+        (c = this.avatarManager.sceneManager) == null || c.lightComponent.removeShadow(this))
     }
-
     removeAvatarFromScene() {
-        this._removeAvatarFromScene(),
-        this._disposeBillBoard()
+        var s;
+        this.component.accessoryMap.forEach(c=>{
+            c.dispose()
+        }
+        ),
+        this.component.accessoryMap.clear();
+        const o = Date.now();
+        this._removeAvatarFromScene(!0),
+        this._disposeBillBoard(),
+        (s = this.avatarManager.sceneManager) == null || s.engineRunTimeStats.timeArray_removeAvatarFromScene.add(Date.now() - o)
     }
-
     _disposeBillBoard() {
         this.bbComponent.disposeBillBoard(this)
     }
-
-    addComponent(e, i, o, s) {
-        return i === "pendant" ? this.component.attachPendant(this, e) : this.component.changeClothesComp(this, e, i, o, s)
+    addComponent(o, s) {
+        switch (s) {
+        case EDressType.PENDANT:
+            return this.component.attachPendant(this, o);
+        case (EDressType.BODY || EDressType.CLOTHES || EDressType.HAIR || EDressType.HEAD || EDressType.SHOES || EDressType.SUIT):
+            return this.component.changeClothesComp(this, o, s);
+        default:
+            return Promise.reject("this type cannot add")
+        }
     }
-
-    removeComponent(e, i) {
-        if (e === "pendant")
-            i ? this.component.detachPendant(i) : this.component.accessories.forEach((o,s)=>{
-                this.component.detachPendant(s)
-            }
-            );
-        else {
-            const o = this.component.resourceIdList.find(s=>s.type == e);
-            o && (this.detachDecoration(o),
-            this.clothesList = this.clothesList.filter(s=>s.type != e))
+    removeComponent(o, s) {
+        o === EDressType.PENDANT ? s ? this.component.detachPendant(s) : this.component.accessoryMap.forEach((c,_)=>{
+            this.component.detachPendant(_)
         }
+        ) : this.component.dressMap.forEach((c,_)=>{
+            c.asset && c.asset.dispose()
+        }
+        )
     }
-
-    getComponentByType(e, i) {
-        if (e === "pendant")
-            if (i) {
-                const o = this.component.accessories.get(i);
-                return o || []
+    getComponentByType(o, s) {
+        if (o === EDressType.PENDANT)
+            if (s) {
+                const c = this.component.accessoryMap.get(s);
+                return c || []
             } else
-                return Array.from(this.component.accessories).map(o=>o[1]);
-        else
-            return this.component.resourceIdList.find(o=>o.type == e)
+                return Array.from(this.component.accessoryMap).map(c=>c[1]);
+        else {
+            const c = [];
+            return this.component.dressMap.forEach((_,b)=>{
+                _.type == o && c.push(_)
+            }
+            ),
+            c
+        }
     }
-
-    _castRay(e) {
-        return new Promise((i,o)=>{
-            var et;
-            const s = ue4Position2Xverse(e)
-              , c = new BABYLON.Vector3(0,-1,0)
-              , d = 1.5 * this.scale
-              , _ = 100 * d
-              , b = d
-              , k = new BABYLON.Vector3(s.x,s.y + b,+s.z)
-              , j = new BABYLON.Ray(k,c,_)
-              , $ = (et = this.avatarManager.sceneManager) == null ? void 0 : et.getGround(e);
-              
-            if (!$ || $.length <= 0)
-            //角色  id= ${this.id}  找不到地面,当前高度为下发高度
-                return console.warn(`\u89D2\u8272 id= ${this.id} \u627E\u4E0D\u5230\u5730\u9762\uFF0C\u5F53\u524D\u9AD8\u5EA6\u4E3A\u4E0B\u53D1\u9AD8\u5EA6`),
-                i(0);
-            let _e = j.intersectsMeshes($);
-            if (_e.length > 0)
-                return i(_e[0].distance - b);
-            if (c.y = 1,
-            _e = j.intersectsMeshes($),
-            _e.length > 0)
-                return i(-(_e[0].distance - b))
-        })
+    setPickBoxScale(o) {
+        return this.bbComponent.setPickBoxScale(o)
     }
-
-    setPickBoxScale(e) {
-        return this.bbComponent.setPickBoxScale(e)
+    setIsPickable(o) {
+        return this.bbComponent.setIsPickable(this, o)
     }
-
-    setIsPickable(e) {
-        return this.bbComponent.setIsPickable(this, e)
+    createPickBoundingbox(o) {
+        return this.bbComponent.createPickBoundingbox(this, o)
     }
-
-    createPickBoundingbox(e) {
-        return this.bbComponent.createPickBoundingbox(this, e)
+    scaleBbox(o) {
+        this.bbComponent.bbox && this.bbComponent.bbox.scale(o)
     }
-
-    scaleBbox(e) {
-        this.bbComponent.bbox && this.bbComponent.bbox.scale(e)
+    rotateTo(o, s, c) {
+        return this.movementComponent.rotateTo(this, o, s, c)
     }
-
-    rotateTo(e, i, o) {
-        return this.stateMachine.rotateTo(this, e, i, o)
+    faceTo(o, s) {
+        return this.movementComponent.lookAt(this, o, s)
     }
-
-    faceTo(e, i) {
-        return this.stateMachine.lookAt(this, e, i)
-    }
-
     removeObserver() {
-        this.stateMachine.disposeObsever()
+        this._observer && (this._observer.unregisterOnNextCall = !0),
+        this.movementComponent.disposeObsever(),
+        this.dispose()
     }
-
-    moveHermite(e, i, o, s, c, d) {
-        return this.stateMachine.moveToHermite(this, e, i, o, s, c, d)
+    moveHermite(o, s, c, _, b, k, j=!0) {
+        return this.movementComponent.moveToHermite(this, o, s, c, _, b, k, j)
     }
-
-    moveCardinal(e, i, o, s, c, d, _=!1) {
-        return this.stateMachine.moveToCardinal(this, e, i, o, s, c, d, _)
+    moveCardinal(o, s, c, _, b, k, j=!1, $=!0) {
+        return this.movementComponent.moveToCardinal(this, o, s, c, _, b, k, j, $)
     }
-
-    move(e, i, o, s, c, d=!1) {
-        return this.stateMachine.moveTo(this, e, i, o, s, c, d)
+    move(o, s, c, _, b, k=!1, j=!0) {
+        return this.movementComponent.moveTo(this, o, s, c, _, b, k, j)
     }
-
-    initNameboard(e=1) {
-        return this.bbComponent.initNameboard(this, e)
+    initNameboard(o=1) {
+        return this.bbComponent.initNameboard(this, o)
     }
-
-    initBubble(e=1) {
-        return this.bbComponent.initBubble(this, e)
+    initBubble(o=1) {
+        return this.bbComponent.initBubble(this, o)
     }
-
-    say(e, {
-        id, isUser, background, 
-        font="Arial", fontsize=38, fontcolor="#ffffff", fontstyle="bold", linesize=22, linelimit, 
-        offsets={x: 0, y: 0, z: 40}, scale=this._avatarScale, compensationZ=11.2, reregistAnyway=!0
-    }) {
-        return this.bbComponent.say(this, e, {
-            id, isUser, background, 
-            font, fontsize, fontcolor, fontstyle, linesize, linelimit,
-            offsets, scale, compensationZ, reregistAnyway
+    say(o, {id: s, isUser: c, background: _, font: b="Arial", fontsize: k=38, fontcolor: j="#ffffff", fontstyle: $="bold", linesize: _e=22, linelimit: et, offsets: tt={
+        x: 0,
+        y: 0,
+        z: 55
+    }, scale: rt=this._avatarScale, compensationZ: it=11.2, reregistAnyway: nt=!0}) {
+        return this.bbComponent.say(this, o, {
+            id: s,
+            isUser: c,
+            background: _,
+            font: b,
+            fontsize: k,
+            fontcolor: j,
+            fontstyle: $,
+            linesize: _e,
+            linelimit: et,
+            offsets: tt,
+            scale: rt,
+            compensationZ: it,
+            reregistAnyway: nt
         })
     }
-    
     silent() {
         return this.bbComponent.silent()
     }
-    
-    setNickName(e, {
-        id, isUser, background, 
-        font="Arial", fontsize=40, fontcolor="#ffffff", fontstyle="bold", linesize=22, linelimit, 
-        offsets={x: 0, y: 0, z: 15}, scale=this._avatarScale, compensationZ=0, reregistAnyway=!1
-    }) {
-        return this.bbComponent.setNickName(this, e, {
-            id, isUser, background,
-            font, fontsize, fontcolor, fontstyle, linesize, linelimit,
-            offsets, scale, compensationZ, reregistAnyway
+    setNickName(o, {id: s, isUser: c, background: _, font: b="Arial", fontsize: k=40, fontcolor: j="#ffffff", fontstyle: $="bold", linesize: _e=22, linelimit: et, offsets: tt={
+        x: 0,
+        y: 0,
+        z: 30
+    }, scale: rt=this._avatarScale, compensationZ: it=0, reregistAnyway: nt=!1}) {
+        return this.bbComponent.setNickName(this, o, {
+            id: s,
+            isUser: c,
+            background: _,
+            font: b,
+            fontsize: k,
+            fontcolor: j,
+            fontstyle: $,
+            linesize: _e,
+            linelimit: et,
+            offsets: tt,
+            scale: rt,
+            compensationZ: it,
+            reregistAnyway: nt
         })
     }
-
-    generateButtons(e=null, i=this._avatarScale, o=85) {
-        return this.bbComponent.generateButtons(this, e, i, o)
+    generateButtons(o=null, s=this._avatarScale, c=100) {
+        return this.bbComponent.generateButtons(this, o, s, c)
     }
-
     clearButtons() {
         return this.bbComponent.clearButtons()
     }
-
-    attachExtraProp(e, i, o, s) {
-        return this.component.addDecoComp(this, e, i, o, s)
-    }
-    
-    showExtra(e) {
-        return this.component.showExtra(e)
-    }
-
-    hideExtra(e) {
-        return this.component.hideExtra(e)
-    }
-
-    disposeExtra() {
-        return this.component.disposeExtra()
-    }
-
-    getSkeletonPositionByName(e) {
-        var i;
+    getSkeletonPositionByName(o) {
+        var s;
         if (this.skeleton) {
-            const o = this.skeleton.bones.find(s=>s.name.replace("Clone of ", "") == e);
-            if (o && o.getTransformNode() && ((i = o.getTransformNode()) == null ? void 0 : i.position)) {
-                const s = o.getTransformNode().position;
+            const c = this.skeleton.bones.find(_=>_.name.replace("Clone of ", "") == o);
+            if (c && c.getTransformNode() && ((s = c.getTransformNode()) == null ? void 0 : s.position)) {
+                const _ = c.getTransformNode().position;
                 return xversePosition2Ue4({
-                    x: s.x,
-                    y: s.y,
-                    z: s.z
+                    x: _.x,
+                    y: _.y,
+                    z: _.z
                 })
             }
         }
     }
-
-    shootTo(e, i, o=2, s=10, c={
+    shootTo(o, s, c=2, _=10, b={
         x: 0,
         y: 0,
         z: 150
     }) {
-        return this.stateMachine.sendObjectTo(this, e, i, o, s, c)
+        return this.movementComponent.sendObjectTo(this, o, s, c, _, b)
+    }
+    generateShowName(o) {
+        return o.split("_")[1]
+    }
+    getMaterialInput() {
+        const o = new Map;
+        return this.rootNode && this.rootNode.getChildMeshes()[3].material instanceof BABYLON.NodeMaterial && this.rootNode.getChildMeshes()[3].material.getInputBlocks().forEach(s=>{
+            s.name.includes("Editable") && (s._storedValue instanceof BABYLON.Color3 || s._storedValue instanceof BABYLON.Color4 ? o.set(this.generateShowName(s.name), s._storedValue.asArray()) : o.set(this.generateShowName(s.name), s._storedValue))
+        }
+        ),
+        o
+    }
+    setMaterialInput(o, s) {
+        s ? this.assetList.forEach(c=>{
+            c.id == s && (c.materialConfig = o)
+        }
+        ) : (this.component.assetList.forEach(c=>{
+            const _ = this.component.dressMap.get(c.id);
+            _ && _.asset.material instanceof BABYLON.NodeMaterial && o.forEach((b,k)=>{
+                const j = _.asset.material.getInputBlockByPredicate($=>$.name == generateOriginalName(k));
+                j && (b.length == 1 ? j._storedValue = b : b.length == 3 ? j._storedValue = BABYLON.Color3.FromArray(b) : b.length == 4 && (j._storedValue = BABYLON.Color3.FromArray(b.slice(0, 3))))
+            }
+            )
+        }
+        ),
+        this.assetList.forEach(c=>{
+            c.materialConfig = o
+        }
+        ))
     }
 }

+ 257 - 258
src/XAvatarBillboardComponent.js

@@ -1,143 +1,140 @@
 import EMeshType from "./enum/EMeshType.js"
 import BillboardStatus from "./enum/BillboardStatus.js"
 import Logger from "./Logger.js"
+import XBillboardManager from "./XBillboardManager.js"
 
 const logger = new Logger('CharacterBillboardComponent')
 
 export default class XAvatarBillboardComponent {
-    constructor(e) {
-        E(this, "_nickName", "");
-        E(this, "_words", "");
-        E(this, "_isNameVisible", !0);
-        E(this, "_isBubbleVisible", !0);
-        E(this, "_isGiftButtonsVisible", !1);
-        E(this, "withinVisualRange", !1);
-        E(this, "_bubble");
-        E(this, "_nameBoard");
-        E(this, "_giftButtons", new Map);
-        E(this, "_buttonTex", new Map);
-        E(this, "_nameLinesLimit", 2);
-        E(this, "_nameLengthPerLine", 16);
-        E(this, "_scene");
-        E(this, "_pickBbox", null);
-        E(this, "bbox");
-        E(this, "_height", .26);
-        E(this, "_attachmentObservers", new Map);
-        E(this, "attachToAvatar", (e,t,r=!1,n={
+    constructor(o) {
+        this._nickName = "",
+        this._words = "",
+        this._isNameVisible = !0,
+        this._isBubbleVisible = !0,
+        this._isGiftButtonsVisible = !1,
+        this.withinVisualRange = !1,
+        this._bubble = void 0,
+        this._nameBoard = void 0,
+        this._giftButtons = new Map,
+        this._buttonTex = new Map,
+        this._nameLinesLimit = 2,
+        this._nameLengthPerLine = 16,
+        this._pickBbox = null,
+        this.bbox = void 0,
+        this._height = .26,
+        this._attachmentObservers = new Map,
+        this.attachToAvatar = (s,c,_=!1,b={
             x: 0,
             y: 0,
             z: 0
-        },o=!1,a,s)=>{
-            const l = e.rootNode;
-            if (this.bbox || e.getBbox(),
-            t && l) {
-                const u = a || t.uniqueId;
-                let c = this._attachmentObservers.get(u);
-                if (c)
-                    if (o)
-                        this._scene.onBeforeRenderObservable.remove(c),
-                        this._attachmentObservers.delete(u);
+        },k=!1,j)=>{
+            const $ = s.rootNode;
+            if (c && $) {
+                let _e = this._attachmentObservers.get(c);
+                if (_e)
+                    if (k)
+                        this._scene.onBeforeRenderObservable.remove(_e),
+                        this._attachmentObservers.delete(c);
                     else
                         return;
-                const h = ue4Position2Xverse(n);
-                r ? (t.setParent(l),
-                t.position = h) : (c = this._scene.onBeforeRenderObservable.add(()=>{
-                    let f = 0;
-                    s ? (f = e.rootNode.rotation.y / Math.PI * 180 + 90,
-                    e.rootNode.rotation.y && (t.rotation.y = e.rootNode.rotation.y)) : f = e.avatarManager.sceneManager.cameraComponent.getCameraPose().rotation.yaw,
-                    f || (f = 0);
-                    const d = new BABYLON.Vector3(0,this._height,0);
-                    e.controller && e.controller.activeAnimation() && e.controller.activeAnimation().animatables[0] && (this._height = d.y = (e.controller.activeAnimation().animatables[0].target.position.y * .01 - .66) * e.scale),
-                    d.y < .07 * e.scale && (d.y = 0),
-                    t.position.x = l.position.x + h.x * Math.sin(f * Math.PI / 180) + h.z * Math.cos(f * Math.PI / 180),
-                    t.position.z = l.position.z + h.x * Math.cos(f * Math.PI / 180) - h.z * Math.sin(f * Math.PI / 180),
-                    t.position.y = l.position.y + this.bbox.maximum.y + h.y + d.y
+                const et = ue4Position2Xverse(b);
+                _ ? (c.setParent($),
+                c.position = et) : (_e = this._scene.onBeforeRenderObservable.add(()=>{
+                    let tt = 0
+                      , rt = Number.NEGATIVE_INFINITY;
+                    s.skeleton && s.skeleton.bones.forEach(nt=>{
+                        const at = nt.name
+                          , ot = s.skeleton.bones.find(st=>st.name.replace("Clone of ", "") == at);
+                        ot && (rt = Math.max(rt, ot.getAbsolutePosition($).y))
+                    }
+                    ),
+                    j ? (tt = s.rootNode.rotation.y / Math.PI * 180 + 90,
+                    s.rootNode.rotation.y && (c.rotation.y = s.rootNode.rotation.y)) : tt = s.avatarManager.sceneManager.cameraComponent.getCameraPose().rotation.yaw,
+                    tt || (tt = 0);
+                    const it = new BABYLON.Vector3(0,this._height,0);
+                    s.controller && s.controller.activeAnimation() && s.controller.activeAnimation().animatables[0] && (this._height = it.y = (s.controller.activeAnimation().animatables[0].target.position.y * .01 - .66) * s.scale),
+                    it.y < .07 * s.scale && (it.y = 0),
+                    c.position.x = $.position.x + et.x * Math.sin(tt * Math.PI / 180) + et.z * Math.cos(tt * Math.PI / 180),
+                    c.position.z = $.position.z + et.x * Math.cos(tt * Math.PI / 180) - et.z * Math.sin(tt * Math.PI / 180),
+                    c.position.y = rt + et.y
                 }
                 ),
-                this._attachmentObservers.set(u, c))
+                this._attachmentObservers.set(c, _e))
             } else
                 logger.error("avatar or attachment not found!")
         }
-        );
-        E(this, "detachFromAvatar", (e,t,r=!1)=>{
-            const n = this._attachmentObservers.get(t.uniqueId);
-            n && this._scene.onBeforeRenderObservable.remove(n),
-            e.rootNode ? (t.setEnabled(!1),
-            t.parent = null,
-            r && t.dispose()) : logger.error("avatar not found!")
+        ,
+        this.detachFromAvatar = (s,c,_=!1)=>{
+            const b = this._attachmentObservers.get(c);
+            b && this._scene.onBeforeRenderObservable.remove(b),
+            s.rootNode ? (c.setEnabled(!1),
+            c.parent = null,
+            _ && c.dispose()) : logger.error("avatar not found!")
         }
-        );
-        E(this, "getBbox", (e,t={})=>{
-            const {isConst: r=!1, changeWithAvatar: n=!1} = t;
-            let {localCenter: o={
+        ,
+        this.getBbox = (s,c={})=>{
+            const {isConst: _=!1, changeWithAvatar: b=!1} = c;
+            let {localCenter: k={
                 x: 0,
                 y: 0,
                 z: 75
-            }, width: a=1.32, height: s=1.5, depth: l=.44} = t;
-            if (n) {
-                const u = e.scale;
-                o = {
-                    x: o.x * u,
-                    y: o.y * u,
-                    z: o.z * u
+            }, width: j=1.32, height: $=1.5, depth: _e=.44} = c;
+            if (b) {
+                const et = s.scale;
+                k = {
+                    x: k.x * et,
+                    y: k.y * et,
+                    z: k.z * et
                 },
-                a *= u,
-                s *= u,
-                l *= u
+                j *= et,
+                $ *= et,
+                _e *= et
             }
-            if (e.rootNode) {
-                let u = new BABYLON.Vector3(0,0,0)
-                  , c = new BABYLON.Vector3(0,0,0);
-                if (r) {
-                    const f = ue4Position2Xverse(o);
-                    u = u.add(f.add(new BABYLON.Vector3(-a / 2,-s / 2,-l / 2))),
-                    c = c.add(f.add(new BABYLON.Vector3(a / 2,s / 2,l / 2)))
-                } else if (u = u.add(new BABYLON.Vector3(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY)),
-                c = c.add(new BABYLON.Vector3(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY)),
-                e.isRender) {
-                    e.rootNode.getChildMeshes().forEach(_=>{
-                        const g = _.getBoundingInfo().boundingBox.minimum
-                          , m = _.getBoundingInfo().boundingBox.maximum;
-                        u.x = Math.min(u.x, g.x),
-                        c.x = Math.max(c.x, m.x),
-                        u.y = Math.min(u.y, g.y),
-                        c.y = Math.max(c.y, m.y),
-                        u.z = Math.min(u.z, g.z),
-                        c.z = Math.max(c.z, m.z)
+            if (s.rootNode) {
+                let et = new BABYLON.Vector3(0,0,0)
+                  , tt = new BABYLON.Vector3(0,0,0);
+                if (_) {
+                    const it = ue4Position2Xverse(k);
+                    et = et.add(it.add(new BABYLON.Vector3(-j / 2,-$ / 2,-_e / 2))),
+                    tt = tt.add(it.add(new BABYLON.Vector3(j / 2,$ / 2,_e / 2)))
+                } else if (et = et.add(new BABYLON.Vector3(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY)),
+                tt = tt.add(new BABYLON.Vector3(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY)),
+                s.isRender) {
+                    s.rootNode.getChildMeshes().forEach(at=>{
+                        const ot = at.getBoundingInfo().boundingBox.minimum
+                          , st = at.getBoundingInfo().boundingBox.maximum;
+                        et.x = Math.min(et.x, ot.x),
+                        tt.x = Math.max(tt.x, st.x),
+                        et.y = Math.min(et.y, ot.y),
+                        tt.y = Math.max(tt.y, st.y),
+                        et.z = Math.min(et.z, ot.z),
+                        tt.z = Math.max(tt.z, st.z)
                     }
                     );
-                    const f = c.x - u.x
-                      , d = c.z - u.z;
-                    u.x -= e.scale * f / 2,
-                    c.x += e.scale * f / 2,
-                    c.y *= e.scale,
-                    u.z -= e.scale * d / 2,
-                    c.z += e.scale * d / 2
+                    const it = tt.x - et.x
+                      , nt = tt.z - et.z;
+                    et.x -= s.scale * it / 2,
+                    tt.x += s.scale * it / 2,
+                    tt.y *= s.scale,
+                    et.z -= s.scale * nt / 2,
+                    tt.z += s.scale * nt / 2
                 } else {
-                    const f = e.avatarManager.getMainAvatar();
-                    f && f.bbComponent.bbox && (u.x = f.bbComponent.bbox.minimum.x,
-                    c.x = f.bbComponent.bbox.maximum.x,
-                    u.y = f.bbComponent.bbox.minimum.y,
-                    c.y = f.bbComponent.bbox.maximum.y,
-                    u.z = f.bbComponent.bbox.minimum.z,
-                    c.z = f.bbComponent.bbox.maximum.z)
-                }
-                const h = e.rootNode.computeWorldMatrix(!0);
-                if (this.bbox ? this.bbox.reConstruct(u, c, h) : this.bbox = new BABYLON.BoundingBox(u,c,h),
-                this._pickBbox == null) {
-                    const f = this.createPickBoundingbox(e, this.bbox);
-                    this.attachToAvatar(e, f.data, !1, {
-                        x: 0,
-                        y: 0,
-                        z: 0
-                    }, !1, "pickbox"),
-                    this._pickBbox = f
+                    const it = s.avatarManager.getMainAvatar();
+                    it && it.bbComponent.bbox && (et.x = it.bbComponent.bbox.minimum.x,
+                    tt.x = it.bbComponent.bbox.maximum.x,
+                    et.y = it.bbComponent.bbox.minimum.y,
+                    tt.y = it.bbComponent.bbox.maximum.y,
+                    et.z = it.bbComponent.bbox.minimum.z,
+                    tt.z = it.bbComponent.bbox.maximum.z)
                 }
+                const rt = s.rootNode.computeWorldMatrix(!0);
+                this.bbox ? this.bbox.reConstruct(et, tt, rt) : this.bbox = new BABYLON.BoundingBox(et,tt,rt),
+                this._pickBbox == null
             } else
                 logger.error("avatar not found!")
         }
-        );
-        this._scene = e
+        ,
+        this._scene = o
     }
     get isNameVisible() {
         return this._isNameVisible
@@ -163,217 +160,219 @@ export default class XAvatarBillboardComponent {
     get nameBoard() {
         return this._nameBoard
     }
-    setNicknameStatus(e) {
-        if (this.nameBoard && this.nameBoard.setStatus(e),
-        e == BillboardStatus.DISPOSE) {
-            const t = this._attachmentObservers.get("nickname");
-            t && (this._scene.onBeforeRenderObservable.remove(t),
-            this._attachmentObservers.delete("nickname"))
-        }
+    setNicknameStatus(o) {
+        this.nameBoard && this.nameBoard.setStatus(o)
     }
-    setBubbleStatus(e) {
-        if (this.bubble && this.bubble.setStatus(e),
-        e == BillboardStatus.DISPOSE) {
-            const t = this._attachmentObservers.get("bubble");
-            t && (this._scene.onBeforeRenderObservable.remove(t),
-            this._attachmentObservers.delete("bubble"))
-        }
+    setBubbleStatus(o) {
+        this.bubble && this.bubble.setStatus(o)
     }
-    setButtonsStatus(e) {
-        this.giftButtons && this.giftButtons.size != 0 && this.giftButtons.forEach(t=>{
-            if (t.setStatus(e),
-            e == BillboardStatus.DISPOSE && t.getMesh()) {
-                const r = "button_" + t.getMesh().xid
-                  , n = this._attachmentObservers.get(r);
-                n && (this._scene.onBeforeRenderObservable.remove(n),
-                this._attachmentObservers.delete(r))
-            }
+    setButtonsStatus(o) {
+        this.giftButtons && this.giftButtons.size != 0 && this.giftButtons.forEach(s=>{
+            s.setStatus(o)
         }
         )
     }
-    setGiftButtonsVisible(e) {
-        this.setButtonsStatus(e ? BillboardStatus.SHOW : BillboardStatus.DISPOSE)
+    setGiftButtonsVisible(o) {
+        this.setButtonsStatus(o ? BillboardStatus.SHOW : BillboardStatus.DISPOSE)
     }
-    dispose(e) {
-        this._attachmentObservers.forEach(t=>{
-            this._scene.onBeforeRenderObservable.remove(t)
+    dispose(o) {
+        this._attachmentObservers.forEach(s=>{
+            this._scene.onBeforeRenderObservable.remove(s)
         }
         ),
         this._attachmentObservers.clear(),
-        this.updateBillboardStatus(e, BillboardStatus.DISPOSE),
+        this.updateBillboardStatus(o, BillboardStatus.DISPOSE),
         this._buttonTex.clear(),
-        this._pickBbox && (e.avatarManager.bboxMeshPool.release(this._pickBbox),
+        this._pickBbox && (o.avatarManager.bboxMeshPool.release(this._pickBbox),
         this._pickBbox = null)
     }
-    updateBillboardStatus(e, t) {
-        this.bbox || e.getBbox(),
-        e.isRender ? (e.setBubbleStatus(t),
-        e.setButtonsStatus(t),
-        e.setNicknameStatus(t)) : (e.setBubbleStatus(BillboardStatus.DISPOSE),
-        e.setButtonsStatus(BillboardStatus.DISPOSE),
-        e.enableNickname ? e.setNicknameStatus(t) : e.setNicknameStatus(BillboardStatus.DISPOSE))
+    updateBillboardStatus(o, s) {
+        var c, _;
+        if (this.bbox || o.getBbox(),
+        s == BillboardStatus.CLEAR) {
+            o.setBubbleStatus(s),
+            o.setButtonsStatus(s),
+            o.setNicknameStatus(s);
+            return
+        }
+        if (o.isRender) {
+            ((c = o.bubble) == null ? void 0 : c.status) != BillboardStatus.DISPOSE && o.setBubbleStatus(s);
+            let b = !0;
+            o.giftButtons.forEach(k=>{
+                k.status == BillboardStatus.DISPOSE && (b = !1)
+            }
+            ),
+            b && o.setButtonsStatus(s),
+            ((_ = o.nameBoard) == null ? void 0 : _.status) != BillboardStatus.DISPOSE && o.setNicknameStatus(s)
+        } else
+            o.setBubbleStatus(BillboardStatus.DISPOSE),
+            o.setButtonsStatus(BillboardStatus.DISPOSE),
+            o.enableNickname ? o.setNicknameStatus(s) : o.setNicknameStatus(BillboardStatus.DISPOSE)
     }
-    disposeBillBoard(e) {
-        this._attachmentObservers.forEach(t=>{
-            this._scene.onBeforeRenderObservable.remove(t)
+    disposeBillBoard(o) {
+        this._attachmentObservers.forEach(s=>{
+            this._scene.onBeforeRenderObservable.remove(s)
         }
         ),
         this._attachmentObservers.clear(),
-        this.updateBillboardStatus(e, BillboardStatus.DISPOSE),
+        this.updateBillboardStatus(o, BillboardStatus.DISPOSE),
         this._buttonTex.clear(),
-        this._pickBbox && (e.avatarManager.bboxMeshPool.release(this._pickBbox),
+        this._pickBbox && (o.avatarManager.bboxMeshPool.release(this._pickBbox),
         this._pickBbox = null)
     }
-    setPickBoxScale(e) {
-        this._pickBbox && this._pickBbox.data && (this._pickBbox.data.scaling = new BABYLON.Vector3(e,e,e))
+    setPickBoxScale(o) {
+        this._pickBbox && this._pickBbox.data && (this._pickBbox.data.scaling = new BABYLON.Vector3(o,o,o))
     }
-    setIsPickable(e, t) {
-        e.rootNode && e.rootNode.getChildMeshes().forEach(r=>{
-            r.isPickable = t
+    setIsPickable(o, s) {
+        o.rootNode && o.rootNode.getChildMeshes().forEach(c=>{
+            c.isPickable = s
         }
         ),
-        this._pickBbox && this._pickBbox.data && (this._pickBbox.data.isPickable = t)
+        this._pickBbox && this._pickBbox.data && (this._pickBbox.data.isPickable = s)
     }
-    initNameboard(e, t=1) {
-        this._nameBoard == null && (this._nameBoard = e.avatarManager.sceneManager.billboardComponent.addBillboard("name-" + e.id, !1, !0)),
-        this._nameBoard.init("nickname", t / 300, t / 300)
+    initNameboard(o, s=1) {
+        this._nameBoard == null && (this._nameBoard = o.avatarManager.sceneManager.billboardComponent.addBillboard("name-" + o.id, !1, !0)),
+        this._nameBoard.init("nickname", s / 300, s / 300),
+        this._nameBoard.owner = this
     }
-    initBubble(e, t=1) {
-        this._bubble == null && (this._bubble = e.avatarManager.sceneManager.billboardComponent.addBillboard("bubble-" + e.id, !1, !0)),
-        e.isRender && this._bubble.init("bubble", t / 250, t / 250)
+    initBubble(o, s=1) {
+        this._bubble == null && (this._bubble = o.avatarManager.sceneManager.billboardComponent.addBillboard("bubble-" + o.id, !1, !0)),
+        this._bubble.owner = this,
+        o.isRender && this._bubble.init("bubble", s / 250, s / 250)
     }
-    say(e, t=this._words, {id: r, isUser: n, background: o, font: a="Arial", fontsize: s=38, fontcolor: l="#ffffff", fontstyle: u="bold", linesize: c=22, linelimit: h, offsets: f={
+    say(o, s=this._words, {id: c, isUser: _, background: b, font: k="Arial", fontsize: j=38, fontcolor: $="#ffffff", fontstyle: _e="bold", linesize: et=22, linelimit: tt, offsets: rt={
         x: 0,
         y: 0,
-        z: 40
-    }, scale: d, compensationZ: _=11.2, reregistAnyway: g=!0}) {
-        (!this.bubble || this.bubble.getMesh() == null) && e.initBubble(),
-        this._words = t;
-        let m;
-        n != null && (m = n ? XBillboardManager.userBubbleUrls : XBillboardManager.npcBubbleUrls),
+        z: 55
+    }, scale: it, compensationZ: nt=11.2, reregistAnyway: at=!0}) {
+        (!this.bubble || this.bubble.getMesh() == null) && o.initBubble(),
+        this._words = s;
+        let ot;
+        _ != null && (ot = _ ? XBillboardManager.userBubbleUrls : XBillboardManager.npcBubbleUrls),
         this._bubble && (this._bubble.DEFAULT_CONFIGS = {
-            id: r,
-            isUser: n,
-            background: o || m,
-            font: a,
-            fontsize: s,
-            fontcolor: l,
-            fontstyle: u,
-            linesize: c,
-            linelimit: h,
-            offsets: f,
-            scale: d,
-            compensationZ: _,
-            reregistAnyway: g
+            id: c,
+            isUser: _,
+            background: b || ot,
+            font: k,
+            fontsize: j,
+            fontcolor: $,
+            fontstyle: _e,
+            linesize: et,
+            linelimit: tt,
+            offsets: rt,
+            scale: it,
+            compensationZ: nt,
+            reregistAnyway: at
         },
-        this._bubble.getMesh() && (this._bubble.drawBillboard({
-            imageList: o || m
+        this._bubble.getMesh() && (o.avatarManager.enableBubble || _ == !1 ? (this._bubble.drawBillboard({
+            imageList: b || ot
         }, {
             texts: this._words,
-            font: a,
-            fontsize: s,
-            fontcolor: l,
-            fontstyle: u,
-            linesize: c
+            font: k,
+            fontsize: j,
+            fontcolor: $,
+            fontstyle: _e,
+            linesize: et
         }, {
-            offsets: f,
-            scale: d,
-            compensationZ: _
+            offsets: rt,
+            scale: it,
+            compensationZ: nt
         }),
-        this.attachToAvatar(e, this._bubble.getMesh(), !1, this._bubble.offsets, g, "bubble"),
-        r && this._bubble.setId(r))),
+        this.attachToAvatar(o, this._bubble.getMesh(), !1, this._bubble.offsets, at)) : this.setBubbleStatus(BillboardStatus.DISPOSE),
+        c && this._bubble.setId(c))),
         this.setButtonsStatus(BillboardStatus.DISPOSE)
     }
     silent() {
         this.setBubbleStatus(BillboardStatus.DISPOSE),
         this._words = ""
     }
-    setNickName(e, t, {id: r, isUser: n, background: o, font: a="Arial", fontsize: s=40, fontcolor: l="#ffffff", fontstyle: u="bold", linesize: c=22, linelimit: h, offsets: f={
+    setNickName(o, s, {id: c, isUser: _, background: b, font: k="Arial", fontsize: j=40, fontcolor: $="#ffffff", fontstyle: _e="bold", linesize: et=22, linelimit: tt, offsets: rt={
         x: 0,
         y: 0,
-        z: 15
-    }, scale: d, compensationZ: _=0, reregistAnyway: g=!1}) {
-        this._nickName = t,
-        (!this.nameBoard || this.nameBoard.getMesh() == null) && this.initNameboard(e),
+        z: 30
+    }, scale: it, compensationZ: nt=0, reregistAnyway: at=!1}) {
+        this._nickName = s,
+        (!this.nameBoard || this.nameBoard.getMesh() == null) && this.initNameboard(o),
         this._nameBoard && this._nameBoard.getMesh() && (this._nameBoard.DEFAULT_CONFIGS = {
-            id: r,
-            isUser: n,
-            background: o,
-            font: a,
-            fontsize: s,
-            fontcolor: l,
-            fontstyle: u,
-            linesize: c,
-            linelimit: h,
-            offsets: f,
-            scale: d,
-            compensationZ: _,
-            reregistAnyway: g
+            id: c,
+            isUser: _,
+            background: b,
+            font: k,
+            fontsize: j,
+            fontcolor: $,
+            fontstyle: _e,
+            linesize: et,
+            linelimit: tt,
+            offsets: rt,
+            scale: it,
+            compensationZ: nt,
+            reregistAnyway: at
         },
-        this._nameBoard.drawBillboard({}, {
+        o.avatarManager.allNicknameStatus == 1 || o.avatarManager.allNicknameStatus == 2 && o.priority == 0 ? (this._nameBoard.drawBillboard({}, {
             texts: this._nickName,
-            font: a,
-            fontsize: s,
-            fontcolor: l,
-            fontstyle: u,
-            linesize: c,
-            linelimit: h
+            font: k,
+            fontsize: j,
+            fontcolor: $,
+            fontstyle: _e,
+            linesize: et,
+            linelimit: tt
         }, {
-            offsets: f,
-            scale: d,
+            offsets: rt,
+            scale: it,
             compensationZ: 0
         }),
-        this.attachToAvatar(e, this._nameBoard.getMesh(), !1, this._nameBoard.offsets, g, "nickname"),
-        r && this._nameBoard.setId(r))
+        this.attachToAvatar(o, this._nameBoard.getMesh(), !1, this._nameBoard.offsets, at)) : this.setNicknameStatus(BillboardStatus.DISPOSE),
+        c && this._nameBoard.setId(c))
     }
-    generateButtons(e, t=null, r, n=85) {
-        if (t && (this._buttonTex = t,
+    generateButtons(o, s=null, c, _=100) {
+        if (s && (this._buttonTex = s,
         this.clearButtons()),
         this._buttonTex.size == 0)
             return;
-        let o = (this._buttonTex.size - 1) / 2;
-        this._buttonTex.forEach((a,s)=>{
-            let l = this._giftButtons.get(s);
-            l || (l = e.avatarManager.sceneManager.billboardComponent.addBillboard("button-" + s + e.id, !0, !1),
-            l.init(s, r / 240, r / 240));
-            const u = {
-                x: r * o * 70,
+        let b = (this._buttonTex.size - 1) / 2;
+        this._buttonTex.forEach((k,j)=>{
+            let $ = this._giftButtons.get(j);
+            $ || ($ = o.avatarManager.sceneManager.billboardComponent.addBillboard("button-" + j + o.id, !0, !1),
+            $.init(j, c / 240, c / 240),
+            $.owner = this);
+            const _e = {
+                x: c * b * 70,
                 y: 0,
-                z: r * (n - 20 * (o * o))
+                z: c * (_ - 20 * (b * b))
             };
-            l.drawBillboard({
-                imageList: [a]
+            $.drawBillboard({
+                imageList: [k]
             }, {}, {
-                offsets: u,
-                scale: r
+                offsets: _e,
+                scale: c
             }),
-            this.attachToAvatar(e, l.getMesh(), !1, l.offsets, !0, "button_" + s),
-            this._giftButtons.set(s, l),
-            o -= 1
+            this.attachToAvatar(o, $.getMesh(), !1, $.offsets, !0),
+            this._giftButtons.set(j, $),
+            b -= 1
         }
         ),
         this.setBubbleStatus(BillboardStatus.DISPOSE)
     }
     clearButtons() {
-        this._giftButtons.forEach(e=>{
-            e.dispose()
+        this._giftButtons.forEach(o=>{
+            o.dispose()
         }
         ),
         this._giftButtons.clear()
     }
-    createPickBoundingbox(e, t) {
-        const r = t.extendSize.x * 2
-          , n = t.extendSize.y * 2
-          , o = t.extendSize.z * 2
-          , a = this._scene
-          , s = Math.max(r, o)
-          , l = e.avatarManager.bboxMeshPool.getFree(a, s, n, s)
-          , u = l.data;
-        return u && (u.position = t.centerWorld,
-        u.setEnabled(!1),
-        u.isPickable = !0,
-        u.xtype = EMeshType.XAvatar,
-        u.xid = e.id),
-        l
+    createPickBoundingbox(o, s) {
+        const c = s.extendSize.x * 2
+          , _ = s.extendSize.y * 2
+          , b = s.extendSize.z * 2
+          , k = this._scene
+          , j = Math.max(c, b)
+          , $ = o.avatarManager.bboxMeshPool.getFree(k, j, _, j)
+          , _e = $.data;
+        return _e && (_e.position = s.centerWorld,
+        _e.setEnabled(!1),
+        _e.isPickable = !0,
+        _e.xtype = EMeshType.XAvatar,
+        _e.xid = o.id),
+        $
     }
 }

+ 141 - 157
src/XAvatarComopnent.js

@@ -1,199 +1,183 @@
 import EMeshType from "./enum/EMeshType.js"
 import Logger from "./Logger.js"
+import XSceneComponent from "./XSceneComponent.js"
 
-const logger = new Logger('CharacterComopnent')
+const logger = new Logger('XAvatarComopnent')
 
-export default class XAvatarComopnent {
+export default class XAvatarComopnent extends XSceneComponent{
     constructor() {
-        this.resourceIdList = [],
+        super(),
         this.skeleton = void 0,
-        this.extraProp = void 0,
-        this.extras = [],
-        this.body = void 0,
-        this.accessories = new Map
+        this.assetList = [],
+        this.virtualbody = void 0,
+        this.dressMap = new Map,
+        this.accessoryMap = new Map
     }
-    addBodyComp(e, i) {
-        return !e.rootNode || i.root.getChildMeshes().length === 0 
-        ? (
-            i.isRender = !1,
-            !1
-        ) : (
-            this.body = i,
-            this.body.root.parent = e.rootNode,
-            i.isRender = !0,
-            this.body.root.getChildMeshes()[0] && (
-                this.body.root.getChildMeshes()[0].xtype = EMeshType.XAvatar,
-                this.body.root.getChildMeshes()[0].xid = e.id
-            ),
-            this.skeleton = i.skeleton,
-            !0
-        )
+    getClassName() {
+        return "XAvatarComponent"
+    }
+    updateAssetList(o) {
+        this.dispose(),
+        this.assetList = o
     }
-    addClothesComp(e, i) {
-        return !e.rootNode || !this.skeleton || !i.root ? (i.isRender = !1,
-        !1) : (i.root.xtype = EMeshType.XAvatar,
-        i.root.xid = e.id,
-        i.isRender = !0,
-        i.root.parent = e.rootNode.getChildMeshes()[0],
-        this.resourceIdList.push(i),
-        i.root.skeleton = this.skeleton,
-        i.root.getChildMeshes().forEach(o=>{
-            o.skeleton = this.skeleton
+    addBodyComp(o, s) {
+        return o.rootNode ? (this.virtualbody = s,
+        this.virtualbody.root.parent = o.rootNode,
+        s.isRender = !0,
+        this.virtualbody.root.getChildMeshes()[0] && (this.virtualbody.root.getChildMeshes()[0].xtype = EMeshType.XAvatar,
+        this.virtualbody.root.getChildMeshes()[0].xid = o.id),
+        this.skeleton = s.skeleton,
+        !0) : (s.isRender = !1,
+        !1)
+    }
+    addClothesComp(o, s) {
+        return !o.rootNode || !this.skeleton || !s.root ? (s.isRender = !1,
+        !1) : (s.root.xtype = EMeshType.XAvatar,
+        s.root.xid = o.id,
+        s.isRender = !0,
+        s.root.parent = o.rootNode.getChildMeshes()[0],
+        this.dressMap.set(s.uId, {
+            id: s.uId,
+            type: s.type,
+            asset: s.root
+        }),
+        s.root.skeleton = this.skeleton,
+        s.root.getChildMeshes().forEach(c=>{
+            c.skeleton = this.skeleton
         }
         ),
         !0)
     }
-    clearClothesComp(e) {
-        e.root.getChildMeshes().forEach(i=>{
-            i.skeleton = null,
-            i.dispose(),
-            i.xid = void 0
+    clearClothesComp(o) {
+        o.asset.getChildMeshes().forEach(s=>{
+            s.skeleton = null,
+            s.material instanceof BABYLON.NodeMaterial && s.material.dispose(void 0, !1),
+            s.dispose(),
+            s.xid = void 0
         }
         ),
-        e.root.dispose(),
-        this.resourceIdList = this.resourceIdList.filter(i=>i.uId != e.uId)
+        o.asset._parentContainer && o.asset._parentContainer.xReferenceCount && (o.asset._parentContainer.xReferenceCount--,
+        o.asset._parentContainer = null),
+        o.asset.material instanceof BABYLON.NodeMaterial && o.asset.material.dispose(void 0, !1),
+        o.asset.dispose(),
+        this.dressMap.delete(o.id)
     }
-    clearAllClothesComps() {
-        this.resourceIdList.forEach(e=>{
-            var i;
-            e.root.parent = null,
-            e.root._parentContainer.xReferenceCount && (e.root._parentContainer.xReferenceCount--,
-            e.root._parentContainer = null),
-            e.isRender = !1,
-            e.isSelected = !1,
-            e.root.getChildMeshes().forEach(o=>{
-                o.skeleton = null,
-                o.dispose()
+    disposeDress() {
+        this.dressMap.forEach((o,s)=>{
+            o && o.asset && (o.asset.parent = null,
+            o.asset.skeleton = null,
+            o.asset._parentContainer && o.asset._parentContainer.xReferenceCount && (o.asset._parentContainer.xReferenceCount--,
+            o.asset._parentContainer = null),
+            o.asset.getChildMeshes().forEach(c=>{
+                c.skeleton = null,
+                c.material instanceof BABYLON.NodeMaterial && c.material.dispose(void 0, !1),
+                c.dispose(void 0, !1)
             }
             ),
-            (i = e.root.skeleton) == null || i.dispose(),
-            e.root.dispose()
+            o.asset.material instanceof BABYLON.NodeMaterial && o.asset.material.dispose(void 0, !1),
+            o.asset.dispose(void 0, !1))
         }
         ),
-        this.resourceIdList = []
+        this.dressMap.clear()
     }
-    dispose(e) {
-        this.body ? (this.body.root._parentContainer.xReferenceCount && (this.body.root._parentContainer.xReferenceCount--,
-        this.body.root._parentContainer = null),
-        this.clearAllClothesComps(),
-        this.body.isRender = !1,
-        this.body.skeleton.dispose(),
-        this.body.skeleton = null,
-        this.body.root.dispose(),
-        this.body = void 0,
+    disposeSkeleton() {
         this.skeleton && (this.skeleton.dispose(),
-        this.skeleton = void 0)) : log$I.warn("[Engine] no body to dispose")
+        this.skeleton = void 0)
+    }
+    disposePendant() {
+        this.accessoryMap.forEach(o=>{
+            o.detachFrom(!0)
+        }
+        ),
+        this.accessoryMap.clear()
+    }
+    dispose(o=!0) {
+        var s;
+        o && (this.disposeSkeleton(),
+        (s = this.virtualbody) == null || s.root.dispose(),
+        this.virtualbody = void 0),
+        this.disposeDress(),
+        this.disposePendant()
     }
-    async attachPendant(e, i) {
-        return Promise.resolve(avatarLoader.pullAndLoadXObject(e.avatarManager.sceneManager, i).then(o=>{
-            const s = o
-              , c = this.accessories.get(s.pointId);
-            return c ? (c.dispose(),
-            this.accessories.set(s.pointId, s),
-            //该挂点当前被占用,已替换该挂点
-            log$I.warn("[Engine] \u8BE5\u6302\u70B9\u5F53\u524D\u88AB\u5360\u7528\uFF0C\u5DF2\u66FF\u6362\u8BE5\u6302\u70B9")) : this.accessories.set(s.pointId, s),
-            s.attachTo(e),
-            s
+    async attachPendant(o, s) {
+        return Promise.resolve(avatarLoader.pullAndLoadXObject(o.avatarManager.sceneManager, s).then(c=>{
+            const _ = c;
+            _.uuid = s;
+            const b = this.accessoryMap.get(_.pointId);
+            return b ? (b.dispose(),
+            this.accessoryMap.set(_.pointId, _),
+            logger.warn("[Engine] 该挂点当前被占用,已替换该挂点")) : this.accessoryMap.set(_.pointId, _),
+            _.attachTo(o),
+            this.assetList.push({
+                id: s,
+                type: EDressType.PENDANT
+            }),
+            _
         }
         ))
     }
-    detachPendant(e, i=!0) {
-        const o = this.accessories.get(e);
-        o && (o.dispose(),
-        this.accessories.delete(e))
+    detachPendant(o, s=!0) {
+        const c = this.accessoryMap.get(o);
+        if (c) {
+            c.dispose(),
+            this.accessoryMap.delete(o);
+            const _ = c.uuid;
+            _ && (this.assetList = this.assetList.filter(b=>b.id != _))
+        }
+    }
+    _getSuitComb(o) {
+        return o == EDressType.CLOTHES || o == EDressType.PANTS ? [EDressType.SUIT] : o == EDressType.SUIT ? [EDressType.CLOTHES, EDressType.PANTS] : []
     }
-    changeClothesComp(e, i, o, s, c) {
-        return new Promise(d=>{
-            if (this.resourceIdList.some(_=>_.name === i))
-                return d();
-            if (e.isHide || !e.isRender)
-                c.concat(o).forEach(b=>{
-                    e.clothesList = e.clothesList.filter(j=>j.type != b);
-                    const k = {
-                        type: o,
-                        id: i,
-                        url: s,
-                        lod: 0
+    changeClothesComp(o, s, c) {
+        return new Promise(_=>{
+            const b = this.dressMap.get(s);
+            if (b && b.asset)
+                return _();
+            if (o.isHide || !o.isRender)
+                this._getSuitComb(c).concat(c).forEach(j=>{
+                    this.assetList = this.assetList.filter(_e=>_e.type != j);
+                    const $ = {
+                        type: c,
+                        id: s
                     };
-                    e.clothesList.push(k)
+                    this.assetList.push($)
                 }
                 ),
-                d();
+                _();
             else {
-                const _ = c.concat(o);
-                e.avatarManager.loadDecoration(o, i, 0).then(b=>{
-                    if (b) {
-                        e.attachDecoration(b);
-                        const k = {
-                            type: o,
-                            id: i,
-                            url: s
+                const k = this._getSuitComb(c).concat(c);
+                o.avatarManager.loadDecoration(c, s, 0).then(j=>{
+                    if (j) {
+                        const $ = [];
+                        this.dressMap.forEach((et,tt)=>{
+                            for (let rt = 0; rt < k.length; ++rt)
+                                et.type === k[rt] && $.push(tt)
+                        }
+                        );
+                        const _e = {
+                            type: c,
+                            id: s
                         };
-                        e.clothesList.push(k),
-                        b.root.setEnabled(!0),
-                        _.forEach(j=>{
-                            const $ = this.resourceIdList.filter(_e=>_e.type === j);
-                            if ($.length > 1) {
-                                const _e = $.filter(et=>et.name === i);
-                                if (_e.length > 1)
-                                    for (let et = 1; et < _e.length; ++et) {
-                                        e.detachDecoration(_e[et]),
-                                        e.clothesList = e.clothesList.filter(rt=>rt.id != _e[et].name);
-                                        const tt = {
-                                            type: o,
-                                            id: i,
-                                            url: s
-                                        };
-                                        e.clothesList.push(tt)
-                                    }
-                            }
-                            $[0] && $[0].name != i && this._readyToDetach(e, o) && (e.detachDecoration($[0]),
-                            e.clothesList = e.clothesList.filter(_e=>_e.id != $[0].name))
+                        o.attachDecoration(j),
+                        j.root.setEnabled(!0),
+                        this.assetList.push(_e),
+                        $.forEach(et=>{
+                            this.assetList = this.assetList.filter(rt=>rt.id != et);
+                            const tt = this.dressMap.get(et);
+                            tt && tt && o.detachDecoration(tt)
                         }
                         )
                     }
-                    return d()
+                    return _()
                 }
                 )
             }
         }
         )
     }
-    _readyToDetach(e, i) {
-        return !((i == "clothes" || i == "pants") && e.clothesList.filter(s=>s.type === "suit").length == 1 && (!e.clothesList.some(s=>s.type === "pants") || !e.clothesList.some(s=>s.type === "clothes")))
-    }
-    addDecoComp(e, i, o, s, c) {
-        if (e.isRender) {
-            const d = e.avatarManager.extraComps.get(i)
-              , _ = d == null ? void 0 : d.clone(i, void 0);
-            if (!d) {
-                log$I.error("\u6CA1\u6709\u5BF9\u5E94\u7684\u7EC4\u4EF6");    //没有对应的组件
-                return
-            }
-            this.extras.push(_);
-            const b = this.skeleton.bones.find(k=>k.name === o);
-            _.position = s,
-            _.rotation = c,
-            _.attachToBone(b, e.rootNode.getChildMeshes()[0])
-        }
-    }
-    showExtra(e) {
-        this.extras.forEach(i=>{
-            i.name.indexOf(e) > 0 && i.setEnabled(!0)
-        }
-        )
-    }
-    hideExtra(e) {
-        this.extras.forEach(i=>{
-            i.name.indexOf(e) > 0 && i.setEnabled(!1)
-        }
-        )
-    }
-    disposeExtra() {
-        this.extras.forEach(e=>{
-            e.dispose()
-        }
-        ),
-        this.extras = []
+    _readyToDetach(o, s) {
+        return !((s == EDressType.CLOTHES || s == EDressType.PANTS) && this.assetList.filter(_=>_.type === EDressType.SUIT).length == 1 && (!this.assetList.some(_=>_.type === EDressType.PANTS) || !this.assetList.some(_=>_.type === EDressType.CLOTHES)))
     }
 }
+
+RegisterXObjectClass("XavatarComponent", XAvatarComopnent);

+ 278 - 272
src/XAvatarLoader.js

@@ -1,20 +1,22 @@
 import Logger from "./Logger.js"
 
-const logger = new Logger('CharacterLoader')
+const logger = new Logger('AvatarManager')
 
 export default class XAvatarLoader {
     constructor() {
         this.containers = new Map,
         this.meshes = new Map,
-        this.animations = new Map,
+        this.assetInfoMap = new Map,
         this.aniPath = new Map,
         this.binPath = new Map,
         this.texPath = new Map,
         this.matPath = new Map,
         this.mshPath = new Map,
         this.rootPath = new Map,
+        this.cachedNodeMat = new Map,
         this.meshTexList = new Map,
         this._enableIdb = !0,
+        this._nodeMatToMesh = new Map,
         this._mappings = new Map,
         this._sharedTex = new Map,
         this.avaliableAnimation = new Map,
@@ -22,348 +24,352 @@ export default class XAvatarLoader {
         this.enableShareAnimation = !0,
         this.fillEmptyLod = !0,
         this.pendantMap = new Map;
-        const e = new BABYLON.GLTFFileLoader;
-        BABYLON.SceneLoader.RegisterPlugin(e),
-        e.preprocessUrlAsync = function(i) {
-            const o = avatarLoader._mappings.get(i);
-            return o ? Promise.resolve(o) : Promise.resolve(i)
+        const o = new BABYLON.GLTFFileLoader;
+        BABYLON.SceneLoader.RegisterPlugin(o),
+        o.preprocessUrlAsync = function(s) {
+            const c = avatarLoader._mappings.get(s);
+            return c ? Promise.resolve(c) : Promise.resolve(s)
         }
     }
-    _parsePendant(e, i) {
-        if (!e || !i) {
+    _parsePendant(o, s) {
+        if (!o || !s) {
             logger.error("[Engine] invalid id or url when loading pendant");
             return
         }
-        const o = ".zip"
-          , s = i.replace(o, "/");
-        this.pendantMap.set(e, s)
+        const c = ".zip"
+          , _ = s.replace(c, "");
+        this.pendantMap.set(o, _)
     }
-    pullAndLoadXObject(e, i) {
-        const o = avatarLoader.pendantMap.get(i);
-        return Tools.LoadFileAsync(o + `${i}.json`, !1).then(s=>{
-            if (!(s instanceof ArrayBuffer))
-                return LoadXObject(o, s).then(c=>c)
+    pullAndLoadXObject(o, s) {
+        const c = avatarLoader.pendantMap.get(s);
+        if (!c)
+            return Promise.reject(`[Engine] cannot find this accessory ${s}`);
+        const _ = c.split("/").pop();
+        return BABYLON.Tools.LoadFileAsync(c + `/${_}.json`, !1).then(b=>{
+            if (!(b instanceof ArrayBuffer))
+                return LoadXObject(c + "/", b, o.urlTransformer).then(k=>k)
         }
         )
     }
-    getParsedUrl(e, i, o, s="") {
-        return new Promise((c,d)=>{
-            if (!o || o.indexOf(".zip") === -1)
-                return c(o);
-            const _ = this.rootPath.get(o);
-            if (_)
-                return c(_);
+    getParsedUrl(o, s, c) {
+        return new Promise((_,b)=>{
+            if (!c || c.indexOf(".zip") === -1)
+                return _(c);
+            const k = this.rootPath.get(c);
+            if (k)
+                return _(k);
             {
-                const b = ".zip"
-                  , k = o.replace(b, "") + COMPONENT_LIST_PREFIX;
-                e.urlTransformer(k, !0).then(j=>{
-                    if (!j)
-                        return d("Loading Failed");
-                    new Response(j).json().then($=>{
-                        var tt, rt, it, nt, ot, at, st;
-                        const _e = o.replace(b, "")
-                          , et = _e + ((tt = $ == null ? void 0 : $.components) == null ? void 0 : tt.url.replace("./", ""));
-                        if (this.rootPath.set(o, et),
-                        $.components ? ($.components.url && this.mshPath.set(i, _e + "/" + ((rt = $ == null ? void 0 : $.components) == null ? void 0 : rt.url.replace("./", ""))),
-                        $.components.url_lod2 && this.mshPath.set(i + "_" + avatarSetting.lod[1].level, _e + "/" + ((it = $ == null ? void 0 : $.components) == null ? void 0 : it.url_lod2.replace("./", ""))),
-                        $.components.url_lod4 && this.mshPath.set(i + "_" + avatarSetting.lod[2].level, _e + "/" + ((nt = $ == null ? void 0 : $.components) == null ? void 0 : nt.url_lod4.replace("./", "")))) : ($.meshes.url && this.mshPath.set(i, _e + "/" + ((ot = $ == null ? void 0 : $.meshes) == null ? void 0 : ot.url.replace("./", ""))),
-                        $.meshes.url_lod2 && this.mshPath.set(i + "_" + avatarSetting.lod[1].level, _e + "/" + ((at = $ == null ? void 0 : $.meshes) == null ? void 0 : at.url_lod2.replace("./", ""))),
-                        $.meshes.url_lod4 && this.mshPath.set(i + "_" + avatarSetting.lod[2].level, _e + "/" + ((st = $ == null ? void 0 : $.meshes) == null ? void 0 : st.url_lod4.replace("./", "")))),
-                        $.materials && $.materials.forEach(ut=>{
-                            const ct = _e + "/" + ut.url;
-                            this.matPath.set(ut.name, ct)
+                const j = ".zip"
+                  , $ = c.replace(j, "") + COMPONENT_LIST_PREFIX;
+                o.urlTransformer($, !0).then(_e=>{
+                    if (!_e)
+                        return b("Loading Failed");
+                    new Response(_e).json().then(et=>{
+                        var it, nt, at, ot, st, lt, ut;
+                        const tt = c.replace(j, "")
+                          , rt = tt + ((it = et == null ? void 0 : et.components) == null ? void 0 : it.url.replace("./", ""));
+                        if (this.rootPath.set(c, rt),
+                        et.components ? (et.components.url && this.mshPath.set(s, tt + "/" + ((nt = et == null ? void 0 : et.components) == null ? void 0 : nt.url.replace("./", ""))),
+                        et.components.url_lod2 && this.mshPath.set(s + "_" + avatarSetting.lod[1].level, tt + "/" + ((at = et == null ? void 0 : et.components) == null ? void 0 : at.url_lod2.replace("./", ""))),
+                        et.components.url_lod4 && this.mshPath.set(s + "_" + avatarSetting.lod[2].level, tt + "/" + ((ot = et == null ? void 0 : et.components) == null ? void 0 : ot.url_lod4.replace("./", "")))) : (et.meshes.url && this.mshPath.set(s, tt + "/" + ((st = et == null ? void 0 : et.meshes) == null ? void 0 : st.url.replace("./", ""))),
+                        et.meshes.url_lod2 && this.mshPath.set(s + "_" + avatarSetting.lod[1].level, tt + "/" + ((lt = et == null ? void 0 : et.meshes) == null ? void 0 : lt.url_lod2.replace("./", ""))),
+                        et.meshes.url_lod4 && this.mshPath.set(s + "_" + avatarSetting.lod[2].level, tt + "/" + ((ut = et == null ? void 0 : et.meshes) == null ? void 0 : ut.url_lod4.replace("./", "")))),
+                        et.materials && et.materials.forEach(ct=>{
+                            const ht = tt + "/" + ct.url;
+                            this.matPath.set(s, ht),
+                            this.matPath.set(s + "_" + avatarSetting.lod[1].level, ht),
+                            this.matPath.set(s + "_" + avatarSetting.lod[2].level, ht),
+                            ct.targetMeshName !== "" && this._nodeMatToMesh.set(ht, ct.targetMeshName)
                         }
                         ),
-                        $.bin) {
-                            const ut = _e + "/" + $.bin.url;
-                            this.binPath.set(i, ut);
-                            const ct = _e + "/" + $.bin.url_lod2;
-                            this.binPath.set(i + "_" + avatarSetting.lod[1].level, ct);
-                            const lt = _e + "/" + $.bin.url_lod4;
-                            this.binPath.set(i + "_" + avatarSetting.lod[2].level, lt)
+                        et.bin) {
+                            const ct = tt + "/" + et.bin.url;
+                            this.binPath.set(s, ct);
+                            const ht = tt + "/" + et.bin.url_lod2;
+                            this.binPath.set(s + "_" + avatarSetting.lod[1].level, ht);
+                            const dt = tt + "/" + et.bin.url_lod4;
+                            this.binPath.set(s + "_" + avatarSetting.lod[2].level, dt)
                         }
-                        return $.textures && $.textures.forEach(ut=>{
-                            const ct = _e + "/" + ut.url;
-                            this.texPath.set(ut.url, ct);
-                            const lt = this.meshTexList.get($.components.url);
-                            ut.type === "png" && (lt ? lt.find(ft=>ft === ut.name) || lt.push(ut.url) : this.meshTexList.set(i, [ut.name]))
+                        return et.textures && et.textures.forEach(ct=>{
+                            const ht = tt + "/" + ct.url;
+                            this.texPath.set(ct.url, ht);
+                            const dt = this.meshTexList.get(et.components.url);
+                            ct.type === "png" && (dt ? dt.find(ft=>ft === ct.name) || dt.push(ct.url) : this.meshTexList.set(s, [ct.name]))
                         }
                         ),
-                        c(et)
+                        _(rt)
                     }
-                    ).catch($=>{
-                        d(`[Engine] parse json file error,${$}`)
+                    ).catch(et=>{
+                        b(`[Engine] parse json file error,${et},id:${s}`)
                     }
                     )
                 }
-                ).catch(j=>{
-                    d(`[Engine] ulrtransform error, cannot find resource in db,${j}`)
+                ).catch(_e=>{
+                    b(`[Engine] ulrtransform error, cannot find resource in db,${_e}`)
                 }
                 )
             }
         }
         )
     }
-    async parse(e, i) {
-        const o = [];
-        i.forEach(s=>{
-            this._setAnimationList(s.id, s.animations),
-            o.push(this.getParsedUrl(e, s.id, s.url)),
-            s.components.forEach(c=>{
-                c.name === "pendant" ? c.units.forEach(d=>{
-                    this._parsePendant(d.id, d.url)
-                }
-                ) : c.units.forEach(d=>{
-                    o.push(this.getParsedUrl(e, d.name, d.url))
+    async parse(o, s) {
+        const c = [];
+        s.forEach(_=>{
+            _.name,
+            _.id,
+            _.componentList.forEach(k=>{
+                const j = k.type;
+                k.unitList.forEach(_e=>{
+                    const et = _e.id
+                      , tt = _e.name
+                      , rt = _e.url
+                      , it = j;
+                    this.assetInfoMap.set(et, {
+                        name: tt,
+                        type: it,
+                        url: rt
+                    }),
+                    it != avatarSetting.pendant && it != avatarSetting.animations && c.push(this.getParsedUrl(o, et, rt)),
+                    it == avatarSetting.animations ? this.aniPath.set(et, rt) : it == avatarSetting.pendant && this._parsePendant(et, rt)
                 }
                 )
             }
             )
         }
         ),
-        await Promise.all(o)
+        Promise.all(c).then(()=>Promise.resolve())
     }
-    _setAnimationList(e, i) {
-        i ? i.forEach(o=>{
-            this.aniPath.set(e + "_" + o.name, o.url)
+    _setAnimationList(o, s) {
+        s ? s.forEach(c=>{
+            this.aniPath.set(o + "_" + c.name, c.url)
         }
         ) : logger.error("[Engine] no animation list exist, please check config for details")
     }
     disposeContainer() {
-        const e = [];
-        this.containers.forEach((i,o)=>{
-            if (i.xReferenceCount < 1) {
-                if (this.enableShareTexture && i.textures.length > 0) {
-                    for (let s = 0; s < i.textures.length; ++s)
-                        i.textures[s].xReferenceCount != null ? i.textures[s].xReferenceCount-- : i.textures[s].xReferenceCount = 0,
-                        i.textures[s]._parentContainer = null;
-                    i.textures = []
+        const o = [];
+        this.containers.forEach((s,c)=>{
+            if (s.xReferenceCount < 1) {
+                if (this.enableShareTexture && s.textures.length > 0) {
+                    for (let _ = 0; _ < s.textures.length; ++_)
+                        s.textures[_].xReferenceCount != null ? s.textures[_].xReferenceCount-- : s.textures[_].xReferenceCount = 0,
+                        s.textures[_]._parentContainer = null;
+                    s.textures = []
                 }
-                e.push(o)
+                o.push(c)
             }
         }
         ),
-        e.forEach(i=>{
-            var o, s;
-            (o = this.containers.get(i)) == null || o.removeAllFromScene(),
-            (s = this.containers.get(i)) == null || s.dispose(),
-            this.containers.delete(i)
+        o.forEach(s=>{
+            var c, _, b;
+            (c = this.containers.get(s)) == null || c.removeAllFromScene(),
+            (_ = this.containers.get(s)) == null || _.meshes.forEach(k=>{
+                k.material instanceof BABYLON.NodeMaterial && k.material.dispose(void 0, !0)
+            }
+            ),
+            (b = this.containers.get(s)) == null || b.dispose(),
+            this.containers.delete(s)
         }
         ),
-        this._sharedTex.forEach((i,o)=>{
-            i.xReferenceCount == 0 && (i.dispose(),
-            this._sharedTex.delete(o))
+        this._sharedTex.forEach((s,c)=>{
+            s.xReferenceCount == 0 && (s.dispose(),
+            this._sharedTex.delete(c))
         }
         )
     }
-    set enableIdb(e) {
-        this._enableIdb = e
+    set enableIdb(o) {
+        this._enableIdb = o
     }
-    getGlbPath(e) {
-        return this.aniPath.get(e + ".glb")
+    getGlbPath(o) {
+        return this.aniPath.get(o + ".glb")
     }
-    getGltfPath(e) {
-        return this.mshPath.get(e + ".gltf")
+    getGltfPath(o) {
+        return this.mshPath.get(o + ".gltf")
     }
-    getPngUrl(e) {
-        return this.texPath.get(e + ".png")
+    getPngUrl(o) {
+        return this.texPath.get(o + ".png")
     }
-    getMeshUrl(e) {
-        return this.mshPath.get(e)
+    getMeshUrl(o) {
+        return this.mshPath.get(o)
     }
-    _getSourceKey(e, i) {
-        return i && avatarSetting.lod[i] ? e + avatarSetting.lod[i].fileName.split(".")[0] : e
+    _getSourceKey(o, s) {
+        return s && avatarSetting.lod[s] ? o + avatarSetting.lod[s].fileName.split(".")[0] : o
     }
-    _getAnimPath(animationName, avatarType) {
-        let o = this.aniPath.get(avatarType + "_animations_" + avatarType.split("_")[1]);
-        return o || (o = this.aniPath.get(avatarType + "_" + animationName)),
-        o
+    _getAnimPath(o, s) {
+        let c = this.aniPath.get(s + "_animations_" + s.split("_")[1]);
+        return c || (c = this.aniPath.get(s + "_" + o)),
+        c
     }
-    load(e, i, o, s) {
-        return this.loadGlb(e, i, o).then(c=>c || Promise.reject("[Engine] container load failed")).catch(()=>Promise.reject("[Engine] container load failed"))
+    load(o, s, c, _) {
+        return this.loadGlb(o, s, c).then(b=>b || Promise.reject(`[Engine] container load failed ${s}`)).catch(b=>Promise.reject(b))
     }
-    _searchAnimation(e, i) {
-        let o;
-        return this.containers.forEach((s,c)=>{
-            const d = i.split("_")[0];
-            c.indexOf(d) != -1 && c.indexOf(e) != -1 && (o = s)
+    _searchAnimation(o, s) {
+        let c;
+        return this.containers.forEach((_,b)=>{
+            const k = s.split("_")[0];
+            b.indexOf(k) != -1 && b.indexOf(o) != -1 && (c = _)
         }
         ),
-        o
+        c
     }
-    loadAnimRes(sceneManager, animationName, avatarType) {
-        const aniModelPath = this._getAnimPath(animationName, avatarType)
-          , aniKey = getAnimationKey(animationName, avatarType);
-        return aniModelPath && this.containers.get(aniModelPath) 
-        ? Promise.resolve(this.containers.get(aniModelPath)) 
-        : aniModelPath
-            ? this._loadGlbFromBlob(sceneManager, aniKey, aniModelPath).then(d=>
-                d.animationGroups.length == 0 
-                ? (
-                    this.containers.delete(aniKey),
-                    d.dispose(),
-                    Promise.reject("container does not contains animation data")
-                ) 
-                : d) 
-            : Promise.reject("no such url")
+    loadAnimRes(o, s) {
+        const c = this.aniPath.get(s)
+          , _ = s;
+        return c && this.containers.get(c) ? Promise.resolve(this.containers.get(c)) : c ? this._loadGlbFromBlob(o, _, c).then(b=>b.animationGroups.length == 0 ? (this.containers.delete(_),
+        b.dispose(),
+        Promise.reject("container does not contains animation data")) : b) : Promise.reject(`[Engine]cannot find resource ${s}`)
     }
-    loadGlb(e, i, o) {
-        let s = this.getMeshUrl(this._getSourceKey(i, o));
-        !s && this.fillEmptyLod && (
-            o = 0,
-            s = this.getMeshUrl(this._getSourceKey(i, o))
-        )
-        return s && this.containers.get(s) 
-            ? Promise.resolve(this.containers.get(s)) 
-            : s 
-                ? this._enableIdb 
-                    ? this._loadGlbFromBlob(e, this._getSourceKey(i, o), s) 
-                    : this._loadGlbFromUrl(e, this._getSourceKey(i, o), s) 
-                : Promise.reject("no such url")
+    loadGlb(o, s, c) {
+        let _ = this.getMeshUrl(this._getSourceKey(s, c));
+        return !_ && this.fillEmptyLod && (c = 0,
+        _ = this.getMeshUrl(this._getSourceKey(s, c))),
+        _ && this.containers.get(_) ? Promise.resolve(this.containers.get(_)) : _ ? this._enableIdb ? this._loadGlbFromBlob(o, this._getSourceKey(s, c), _) : this._loadGlbFromUrl(o, this._getSourceKey(s, c), _) : Promise.reject("no such url")
     }
-    loadGltf(e, i, o, s) {
-        const c = this._getSourceKey(i, o || 0);
-        let d = this.getGltfPath(c);
-        !d && this.fillEmptyLod && (d = this.getGltfPath(i))
-        return d && this.containers.get(d) 
-            ? Promise.resolve(this.containers.get(d)) 
-            : this._enableIdb 
-                ? this._loadGltfFromBlob(e, i, o, s) 
-                : d 
-                    ? this._loadGltfFromUrl(e, i, d.replace(i + ".gltf", "")) 
-                    : Promise.reject()
+    loadGltf(o, s, c, _) {
+        const b = this._getSourceKey(s, c || 0);
+        let k = this.getGltfPath(b);
+        return !k && this.fillEmptyLod && (k = this.getGltfPath(s)),
+        k && this.containers.get(k) ? Promise.resolve(this.containers.get(k)) : this._enableIdb ? this._loadGltfFromBlob(o, s, c, _) : k ? this._loadGltfFromUrl(o, s, k.replace(s + ".gltf", "")) : Promise.reject()
     }
     loadSubsequence() {}
     loadVAT() {}
-    getResourceName(e) {
-        return this.meshTexList.get(e)
+    getResourceName(o) {
+        return this.meshTexList.get(o)
     }
-    _loadGltfFromUrl(e, i, o) {
-        return BABYLON.SceneLoader.LoadAssetContainerAsync(o, i + ".gltf", e.Scene, null, ".gltf")
+    _loadGltfFromUrl(o, s, c) {
+        return BABYLON.SceneLoader.LoadAssetContainerAsync(c, s + ".gltf", o.Scene, null, ".gltf")
     }
-    _loadGlbFromBlob(sceneManager, i, aniModelPath) {
-        return sceneManager.urlTransformer(aniModelPath)
-        .then(path=>BABYLON.SceneLoader.LoadAssetContainerAsync("", path, sceneManager.Scene, null, ".glb").then(model => {
-            if (model) {
-                if (this.containers.get(aniModelPath))
-                    return model.dispose(),
-                    this.containers.get(aniModelPath);
-                model.addAllToScene()
-                if (this.enableShareTexture && model.textures.length > 0) {
-                    const d = [];
-                    let hasSameTex = false;
-                    model.meshes.forEach(mesh=>{
-                        if (mesh.material) {
-                            const albedoTexture = mesh.material._albedoTexture;
-                            if (albedoTexture) {
-                                let albedoTexName = albedoTexture.name;
-                                albedoTexName = albedoTexName.replace(" (Base Color)", "").split(".")[0];
-                                const oldTex = this._sharedTex.get(albedoTexName);
-                                oldTex ? (
-                                    hasSameTex = true,
-                                    mesh.material._albedoTexture = oldTex,
-                                    d.push(oldTex),
-                                    oldTex._parentContainer = model,
-                                    oldTex.xReferenceCount++
-                                ) : (
-                                    this._sharedTex.set(albedoTexName, albedoTexture),
-                                    model.textures[0].xReferenceCount = 1
-                                )
-                            }
-                        }
-                    })
-                    hasSameTex && (
-                        model.textures.forEach(tex=>{
-                            sceneManager.Scene.removeTexture(tex)
-                            // tex.dispose()      // zeg 这个加上会导致贴图丢失
-                        }),
-                        model.textures = d
-                    )
+    _loadGlbFromBlob(o, s, c) {
+        const _ = o.urlTransformer(c).then(j=>BABYLON.SceneLoader.LoadAssetContainerAsync("", j, o.Scene, null, ".glb"))
+          , b = this.matPath.get(s);
+        let k;
+        if (b) {
+            const j = new BABYLON.NodeMaterial(`material_${s}`,o.Scene,{
+                emitComments: !1
+            })
+              , et = (o == null ? void 0 : o.urlTransformer(b)).then(tt=>j.loadAsync(tt)).then(()=>(this.cachedNodeMat.get(b) ? (j.build(!1, !1),
+            j.buildId = this.cachedNodeMat.get(b)) : (this.cachedNodeMat.set(b, j.buildId),
+            j.build(!1, !0)),
+            j));
+            k = Promise.all([et, _]).then(([tt,rt])=>(this._nodeMatToMesh.get(b) ? rt.meshes.forEach(it=>{
+                var nt;
+                this._nodeMatToMesh.get(b) == it.name && ((nt = it.material) == null || nt.dispose(!0, !1),
+                it.material = tt)
+            }
+            ) : rt.meshes.forEach(it=>{
+                var nt;
+                (nt = it.material) == null || nt.dispose(!0, !1),
+                it.material = tt
+            }
+            ),
+            rt))
+        } else
+            k = _.then(j=>(this.enableShareTexture && j.textures.length > 0 && j.meshes.forEach($=>{
+                if ($.material) {
+                    const _e = $.material._albedoTexture;
+                    if (_e) {
+                        let et = _e.name;
+                        et = et.replace(" (Base Color)", "").split(".")[0];
+                        const tt = this._sharedTex.get(et);
+                        !tt || tt.uid == _e.uid ? (this._sharedTex.set(et, _e),
+                        j.textures[0].xReferenceCount = 1) : ($.material._albedoTexture = tt,
+                        j.textures = j.textures.filter(rt=>rt.uid != _e.uid),
+                        o.Scene.removeTexture(_e),
+                        _e.dispose(),
+                        tt._parentContainer = j,
+                        tt.xReferenceCount++)
+                    }
                 }
-                model.xReferenceCount = 0
-                model.meshes.forEach(mesh=>{
-                    mesh.setEnabled(false)
-                })
-                this.containers.set(aniModelPath, model)
-                return Promise.resolve(model)
-            } else
-                return Promise.reject("glb file load failed")
+            }
+            ),
+            j));
+        return k.then(j=>{
+            j.xReferenceCount = 0,
+            j.meshes.forEach($=>{
+                $.setEnabled(!1)
+            }
+            ),
+            this.containers.set(c, j)
         }
-        ))
+        ),
+        k
     }
-    _loadGlbFromUrl(e, i, o) {
-        return BABYLON.SceneLoader.LoadAssetContainerAsync("", o, e.Scene, null, ".glb").then(s=>s ? (s.addAllToScene(),
-        s.meshes.forEach(c=>{
-            c.setEnabled(!1)
+    _loadGlbFromUrl(o, s, c) {
+        return BABYLON.SceneLoader.LoadAssetContainerAsync("", c, o.Scene, null, ".glb").then(_=>_ ? (_.addAllToScene(),
+        _.meshes.forEach(b=>{
+            b.setEnabled(!1)
         }
         ),
-        this.enableShareTexture && s.textures.length > 0 ? (s.meshes.forEach(c=>{
-            if (c.material) {
-                const d = c.material._albedoTexture;
-                if (d) {
-                    let _ = d.name;
-                    _ = _.replace(" (Base Color)", "").split(".")[0];
-                    const b = this._sharedTex.get(_);
-                    b ? (c.material._albedoTexture = b,
-                    b.xReferenceCount++) : (this._sharedTex.set(_, d),
-                    s.textures[0].xReferenceCount = 1)
+        this.enableShareTexture && _.textures.length > 0 ? (_.meshes.forEach(b=>{
+            if (b.material) {
+                const k = b.material._albedoTexture;
+                if (k) {
+                    let j = k.name;
+                    j = j.replace(" (Base Color)", "").split(".")[0];
+                    const $ = this._sharedTex.get(j);
+                    !$ || $.uid == k.uid ? (this._sharedTex.set(j, k),
+                    _.textures[0].xReferenceCount = 1) : (b.material._albedoTexture = $,
+                    _.textures = _.textures.filter(_e=>_e.uid != k.uid),
+                    o.Scene.removeTexture(k),
+                    k.dispose(),
+                    $._parentContainer = _,
+                    $.xReferenceCount++)
                 }
             }
         }
         ),
-        s.xReferenceCount = 0,
-        this.containers.set(o, s),
-        Promise.resolve(s)) : Promise.reject("glb file load failed"),
-        s.xReferenceCount = 0,
-        this.containers.set(o, s),
-        Promise.resolve(s)) : Promise.reject("glb file load failed"))
+        _.xReferenceCount = 0,
+        this.containers.set(c, _),
+        Promise.resolve(_)) : Promise.reject("glb file load failed"),
+        _.xReferenceCount = 0,
+        this.containers.set(c, _),
+        Promise.resolve(_)) : Promise.reject("glb file load failed"))
     }
-    _loadGltfFromBlob(e, i, o, s) {
-        return new Promise((c,d)=>{
-            const _ = [];
-            let b = this._getSourceKey(i, o)
-              , k = this.getGltfPath(b);
-            if (!k && this.fillEmptyLod && (o = 0,
-            b = this._getSourceKey(i, o),
-            k = this.getGltfPath(b)),
-            !k)
-                return d(`[Engine] gltf path incorrect ${b},cancel.`);
-            const j = this.mshPath.get(b + ".gltf");
-            if (!j)
-                return d("cannot find asset mshPath");
-            const $ = this.binPath.get(b + ".bin");
-            if (!$)
-                return d("cannot find asset binPath");
-            if (!s) {
-                const tt = this.meshTexList.get(i);
-                if (!tt || tt.length == 0)
-                    return d("cannot find texture");
-                s = tt[0]
-            }
-            const _e = this.texPath.get(s + ".png");
-            if (!_e)
-                return d();
-            const et = this.texPath.get(s + "-astc.ktx");
+    _loadGltfFromBlob(o, s, c, _) {
+        return new Promise((b,k)=>{
+            const j = [];
+            let $ = this._getSourceKey(s, c)
+              , _e = this.getGltfPath($);
+            if (!_e && this.fillEmptyLod && (c = 0,
+            $ = this._getSourceKey(s, c),
+            _e = this.getGltfPath($)),
+            !_e)
+                return k(`[Engine] gltf path incorrect ${$},cancel.`);
+            const et = this.mshPath.get($ + ".gltf");
             if (!et)
-                return d();
-            _.push(this._blobMapping(e, j)),
-            _.push(this._blobMapping(e, $)),
-            _.push(this._blobMapping(e, _e)),
-            _.push(this._blobMapping(e, et)),
-            Promise.all(_).then(()=>{
-                const tt = k.replace(b + ".gltf", "");
-                BABYLON.SceneLoader.LoadAssetContainerAsync(tt, b + ".gltf", e.Scene, null, ".gltf").then(rt=>{
-                    var nt;
-                    this.containers.set(k, rt),
-                    rt.addAllToScene(),
-                    rt.meshes.forEach(ot=>{
-                        ot.setEnabled(!1)
+                return k("cannot find asset mshPath");
+            const tt = this.binPath.get($ + ".bin");
+            if (!tt)
+                return k("cannot find asset binPath");
+            if (!_) {
+                const nt = this.meshTexList.get(s);
+                if (!nt || nt.length == 0)
+                    return k("cannot find texture");
+                _ = nt[0]
+            }
+            const rt = this.texPath.get(_ + ".png");
+            if (!rt)
+                return k();
+            const it = this.texPath.get(_ + "-astc.ktx");
+            if (!it)
+                return k();
+            j.push(this._blobMapping(o, et)),
+            j.push(this._blobMapping(o, tt)),
+            j.push(this._blobMapping(o, rt)),
+            j.push(this._blobMapping(o, it)),
+            Promise.all(j).then(()=>{
+                const nt = _e.replace($ + ".gltf", "");
+                BABYLON.SceneLoader.LoadAssetContainerAsync(nt, $ + ".gltf", o.Scene, null, ".gltf").then(at=>{
+                    var st;
+                    this.containers.set(_e, at),
+                    at.addAllToScene(),
+                    at.meshes.forEach(lt=>{
+                        lt.setEnabled(!1)
                     }
                     );
-                    const it = this._sharedTex.get(i);
-                    it ? ((nt = rt.meshes[1].material._albedoTexture) == null || nt.dispose(),
-                    rt.meshes[1].material._albedoTexture = it) : this._sharedTex.set(i, rt.meshes[1].material._albedoTexture),
-                    c(rt)
+                    const ot = this._sharedTex.get(s);
+                    ot ? ((st = at.meshes[1].material._albedoTexture) == null || st.dispose(),
+                    at.meshes[1].material._albedoTexture = ot) : this._sharedTex.set(s, at.meshes[1].material._albedoTexture),
+                    b(at)
                 }
                 )
             }
@@ -371,10 +377,10 @@ export default class XAvatarLoader {
         }
         )
     }
-    _blobMapping(e, i) {
-        return new Promise((o,s)=>{
-            e.urlTransformer(i).then(c=>c ? (this._mappings.set(i, c),
-            o(i)) : s(`[Engine] url urlTransformer parse error ${i}`))
+    _blobMapping(o, s) {
+        return new Promise((c,_)=>{
+            o.urlTransformer(s).then(b=>b ? (this._mappings.set(s, b),
+            c(s)) : _(`[Engine] url urlTransformer parse error ${s}`))
         }
         )
     }

Diferenças do arquivo suprimidas por serem muito extensas
+ 707 - 558
src/XAvatarManager.js


+ 149 - 139
src/XBillboard.js

@@ -4,36 +4,38 @@ import Logger from "./Logger.js"
 
 const logger = new Logger('Billboard')
 export default class XBillboard {
-    constructor(e, t=!1, r=!1) {
-        E(this, "_mesh", null);
-        E(this, "_texture", null);
-        E(this, "_scalingFactor", 1);
-        E(this, "offsets", null);
-        E(this, "_pickable");
-        E(this, "_background", null);
-        E(this, "_billboardManager");
-        E(this, "poolobj", null);
-        E(this, "_usePool");
-        E(this, "_initMeshScale", new BABYLON.Vector3(1,1,1));
-        E(this, "_status", -1);
-        E(this, "_stageChanged", !1);
-        E(this, "DEFAULT_CONFIGS", {});
-        this._billboardManager = e,
-        this._pickable = t,
-        this._usePool = r
-    }
-    set scalingFactor(e) {
-        this._scalingFactor = e
-    }
-    set background(e) {
-        this._background = e
+    constructor(o, s=!1, c=!1) {
+        this._mesh = null,
+        this._texture = null,
+        this._scalingFactor = 1,
+        this.offsets = null,
+        this._background = null,
+        this.poolobj = null,
+        this._initMeshScale = new BABYLON.Vector3(1,1,1),
+        this._status = -1,
+        this._stageChanged = !1,
+        this.DEFAULT_CONFIGS = {},
+        this._billboardManager = o,
+        this._pickable = s,
+        this._usePool = c,
+        this._id = ""
+    }
+    set scalingFactor(o) {
+        this._scalingFactor = o
+    }
+    set background(o) {
+        this._background = o
     }
     get size() {
         return -1
     }
-    setStatus(e) {
-        e != this._status && (this._stageChanged = !0,
-        this._status = e)
+    setStatus(o) {
+        if (this._status == 2) {
+            this._stageChanged = !0;
+            return
+        }
+        o != this._status && (this._stageChanged = !0,
+        this._status = o)
     }
     get status() {
         return this._status
@@ -41,25 +43,26 @@ export default class XBillboard {
     get stageChanged() {
         return this._stageChanged
     }
-    set stageChanged(e) {
-        this._stageChanged = e
+    set stageChanged(o) {
+        this._stageChanged = o
     }
-    init(e="", t=.001, r=.001, n=!1) {
-        const o = this._billboardManager.sceneManager.Scene;
+    init(o="", s=.001, c=.001, _=!1) {
+        const b = this._billboardManager.sceneManager.Scene;
         if (this._usePool) {
-            const a = this._billboardManager.billboardPool.getFree(o, t, r, n);
-            this._mesh = a.data,
+            const k = this._billboardManager.billboardPool.getFree(b, s, c, _);
+            this._mesh = k.data,
             this._mesh.isPickable = this._pickable,
-            this._mesh.xid = e,
+            this._id = o,
+            this._mesh.xid = o,
             this._mesh.xtype = EMeshType.XBillboard,
             this._texture = this._mesh.material.diffuseTexture,
-            this.poolobj = a
+            this.poolobj = k
         } else
-            this._mesh = this._billboardManager.createBillboardAsset(o, n);
+            this._mesh = this._billboardManager.createBillboardAsset(b, _);
         this._mesh.isPickable = this._pickable,
-        this._initMeshScale.x = t * 1e3,
-        this._initMeshScale.y = r * 1e3,
-        this._mesh.xid = e,
+        this._initMeshScale.x = s * 1e3,
+        this._initMeshScale.y = c * 1e3,
+        this._mesh.xid = o,
         this._mesh.xtype = EMeshType.XBillboard,
         this._texture = this._mesh.material.diffuseTexture,
         this.setStatus(1),
@@ -77,33 +80,33 @@ export default class XBillboard {
     getMesh() {
         return this._mesh
     }
-    updateImage(e) {
-        return new Promise(t=>{
+    updateImage(o) {
+        return new Promise(s=>{
             if (this._texture == null) {
                 logger.error("[Engine]Billboard texture not found");
                 return
             }
-            const r = this._mesh
-              , n = this._texture
-              , o = this._scalingFactor
-              , a = this._initMeshScale.x
-              , s = this._initMeshScale.y
-              , l = this._texture.getContext()
-              , u = this._texture.getSize();
-            l.clearRect(0, 0, u.width, u.height);
-            const c = new Image;
-            c.crossOrigin = "anonymous",
-            c.src = e,
-            c.onload = ()=>{
-                const h = c.width * o
-                  , f = c.height * o;
-                r.scaling.x = h * a,
-                r.scaling.y = f * s,
-                n.scaleTo(h, f),
-                l.drawImage(c, 0, 0, h, f),
-                n.hasAlpha = !0,
-                n.update(),
-                t()
+            const c = this._mesh
+              , _ = this._texture
+              , b = this._scalingFactor
+              , k = this._initMeshScale.x
+              , j = this._initMeshScale.y
+              , $ = this._texture.getContext()
+              , _e = this._texture.getSize();
+            $.clearRect(0, 0, _e.width, _e.height);
+            const et = new Image;
+            et.crossOrigin = "anonymous",
+            et.src = o,
+            et.onload = ()=>{
+                const tt = et.width * b
+                  , rt = et.height * b;
+                c.scaling.x = tt * k,
+                c.scaling.y = rt * j,
+                _.scaleTo(tt, rt),
+                $.drawImage(et, 0, 0, tt, rt),
+                _.hasAlpha = !0,
+                _.update(),
+                s()
             }
         }
         )
@@ -116,113 +119,120 @@ export default class XBillboard {
         this._mesh && (this._mesh.setEnabled(!1),
         this._mesh.isPickable = !1)
     }
-    setId(e) {
-        this._mesh && (this._mesh.xid = e)
+    setId(o) {
+        this._mesh && (this._mesh.xid = o),
+        this._id = o
+    }
+    getId() {
+        return this._id
     }
-    setPosition(e) {
-        if (e && this._mesh) {
-            const t = ue4Position2Xverse(e);
-            this._mesh.position = t
+    setPosition(o) {
+        if (o && this._mesh) {
+            const s = ue4Position2Xverse(o);
+            this._mesh.position = s
         }
     }
-    updateText(e, t, r=!0, n=[], o=30, a="monospace", s="black", l="bold", u) {
+    updateText(o, s, c=!0, _=[], b=30, k="monospace", j="black", $="bold", _e) {
         if (this._texture == null) {
             logger.error("[Engine]Billboard texture not found");
             return
         }
-        const c = this._texture
-          , h = this._mesh
-          , f = this._scalingFactor
-          , d = this._initMeshScale.x
-          , _ = this._initMeshScale.y;
-        if (e != "") {
-            const g = this._texture.getContext()
-              , m = this._texture.getSize();
-            g.clearRect(0, 0, m.width, m.height);
-            const v = new Image;
-            if (r) {
-                t != null ? t ? this._background = this._billboardManager.userBackGroundBlob : this._background = this._billboardManager.npcBackGroundBlob : this._background || (this._background = this._billboardManager.userBackGroundBlob);
-                let y = e
-                  , b = u && u < n.length - 1 ? u : n.length - 1;
+        const et = this._texture
+          , tt = this._mesh
+          , rt = this._scalingFactor
+          , it = this._initMeshScale.x
+          , nt = this._initMeshScale.y;
+        if (o != "") {
+            const at = this._texture.getContext()
+              , ot = this._texture.getSize();
+            at.clearRect(0, 0, ot.width, ot.height);
+            const st = new Image;
+            if (c) {
+                s != null ? s ? this._background = this._billboardManager.userBackGroundBlob : this._background = this._billboardManager.npcBackGroundBlob : this._background || (this._background = this._billboardManager.userBackGroundBlob);
+                let lt = o
+                  , ut = _e && _e < _.length - 1 ? _e : _.length - 1;
                 if (this._background) {
-                    if (b > this._background.length) {
-                        for (let T = 0; T < b - this._background.length; T++)
-                            n.pop();
-                        b = n.length - 1,
-                        y = e.slice(0, n[b] - 1) + String.fromCharCode(8230)
+                    if (ut > this._background.length) {
+                        for (let ct = 0; ct < ut - this._background.length; ct++)
+                            _.pop();
+                        ut = _.length - 1,
+                        lt = o.slice(0, _[ut] - 1) + String.fromCharCode(8230)
                     }
-                    v.crossOrigin = "anonymous",
-                    v.src = this._background[b - 1],
-                    v.onload = function() {
-                        const T = v.width * f
-                          , C = v.height * f;
-                        h.scaling.x = T * d,
-                        h.scaling.y = C * _,
-                        c.scaleTo(T, C),
-                        g.textAlign = "center",
-                        g.textBaseline = "middle",
-                        g.drawImage(v, 0, 0, T, C);
-                        for (let A = 0; A < b; A++)
-                            c.drawText(y.slice(n[0 + A], n[1 + A]), T / 2, C * (A + 1) / (b + 1) + (A - (b - 1) / 2) * f * 10, l + " " + o * f + "px " + a, s, "transparent", !0);
-                        c.hasAlpha = !0
+                    st.crossOrigin = "anonymous",
+                    st.src = this._background[ut - 1],
+                    st.onload = function() {
+                        const ct = st.width * rt
+                          , ht = st.height * rt;
+                        tt.scaling.x = ct * it,
+                        tt.scaling.y = ht * nt,
+                        et.scaleTo(ct, ht),
+                        at.textAlign = "center",
+                        at.textBaseline = "middle",
+                        at.drawImage(st, 0, 0, ct, ht);
+                        for (let dt = 0; dt < ut; dt++)
+                            et.drawText(lt.slice(_[0 + dt], _[1 + dt]), ct / 2, ht * (dt + 1) / (ut + 1) + (dt - (ut - 1) / 2) * rt * 10, $ + " " + b * rt + "px " + k, j, "transparent", !0);
+                        et.hasAlpha = !0
                     }
                 }
             } else {
-                const y = u && u < n.length - 1 ? u : n.length - 1
-                  , b = 480 * f
-                  , T = 60 * f * y;
-                this._mesh.scaling = new BABYLON.Vector3(b * d,T * _,1),
-                c.scaleTo(b, T);
-                const C = c.getContext();
-                C.textAlign = "center",
-                C.textBaseline = "middle";
-                for (let A = 0; A < y; A++)
-                    c.drawText(e.slice(n[0 + A], n[1 + A]), b / 2 + 2 * f, T * (A + 1) / (y + 1) + (A - (y - 1) / 2) * f * 10 + 2 * f, l + " " + o * f + "px " + a, "#333333", "transparent", !0),
-                    c.drawText(e.slice(n[0 + A], n[1 + A]), b / 2, T * (A + 1) / (y + 1) + (A - (y - 1) / 2) * f * 10, l + " " + o * f + "px " + a, s, "transparent", !0);
-                c.hasAlpha = !0
+                const lt = _e && _e < _.length - 1 ? _e : _.length - 1
+                  , ut = 480 * rt
+                  , ct = 60 * rt * lt;
+                this._mesh.scaling = new BABYLON.Vector3(ut * it,ct * nt,1),
+                et.scaleTo(ut, ct);
+                const ht = et.getContext();
+                ht.textAlign = "center",
+                ht.textBaseline = "middle";
+                for (let dt = 0; dt < lt; dt++)
+                    setTimeout(()=>{
+                        et.drawText(o.slice(_[0 + dt], _[1 + dt]), ut / 2 + 2 * rt, ct * (dt + 1) / (lt + 1) + (dt - (lt - 1) / 2) * rt * 10 + 2 * rt, $ + " " + b * rt + "px " + k, "#333333", "transparent", !0),
+                        et.drawText(o.slice(_[0 + dt], _[1 + dt]), ut / 2, ct * (dt + 1) / (lt + 1) + (dt - (lt - 1) / 2) * rt * 10, $ + " " + b * rt + "px " + k, j, "transparent", !0)
+                    }
+                    , 0);
+                et.hasAlpha = !0
             }
         } else
             this.clearText()
     }
-    drawBillboard(e, t, r) {
-        var m;
-        const {imageList: n} = e
-          , {texts: o, font: a="monospace", fontsize: s=40, fontcolor: l="#ffffff", fontstyle: u="", linesize: c=20, linelimit: h} = t
-          , {position: f, offsets: d, scale: _, compensationZ: g=0} = r;
-        if (this.scalingFactor = _ || 1,
-        d && (this.offsets = {
-            x: d.x * this._scalingFactor,
-            y: d.y * this._scalingFactor,
-            z: d.z * this._scalingFactor
+    drawBillboard(o, s, c) {
+        var ot;
+        const {imageList: _} = o
+          , {texts: b, font: k="monospace", fontsize: j=40, fontcolor: $="#ffffff", fontstyle: _e="", linesize: et=20, linelimit: tt} = s
+          , {position: rt, offsets: it, scale: nt, compensationZ: at=0} = c;
+        if (this.scalingFactor = nt || 1,
+        it && (this.offsets = {
+            x: it.x * this._scalingFactor,
+            y: it.y * this._scalingFactor,
+            z: it.z * this._scalingFactor
         }),
         this.offsets || (this.offsets = {
             x: 0,
             y: 0,
             z: 0
         }),
-        this.setPosition(f),
-        n && !o)
-            (m = this._billboardManager.sceneManager) == null || m.urlTransformer(n[0]).then(v=>{
-                this.updateImage(v)
+        this.setPosition(rt),
+        _ && !b)
+            (ot = this._billboardManager.sceneManager) == null || ot.urlTransformer(_[0]).then(st=>{
+                this.updateImage(st)
             }
             );
-        else if (o && !n) {
-            const [v,y] = getStringBoundaries(o, c, XBillboardManager.alphaWidthMap);
-            this.offsets.z += this._scalingFactor * g * (y.length - 1),
-            this.updateText(v, void 0, !1, y, s, a, l, u, h)
-        } else if (o && n) {
-            this.background = n;
-            const [v,y] = getStringBoundaries(o, c, XBillboardManager.alphaWidthMap);
-            this.offsets.z += this._scalingFactor * g * (y.length - 1),
-            this.updateText(v, void 0, !0, y, s, a, l, u, h)
+        else if (b && !_) {
+            const [st,lt] = getStringBoundaries(b, et, XBillboardManager.alphaWidthMap);
+            this.offsets.z += this._scalingFactor * at * (lt.length - 1),
+            this.updateText(st, void 0, !1, lt, j, k, $, _e, tt)
+        } else if (b && _) {
+            this.background = _;
+            const [st,lt] = getStringBoundaries(b, et, XBillboardManager.alphaWidthMap);
+            this.offsets.z += this._scalingFactor * at * (lt.length - 1),
+            this.updateText(st, void 0, !0, lt, j, k, $, _e, tt)
         }
         this.setStatus(1)
     }
     clearText() {
         if (this._texture != null) {
-            const e = this._texture.getContext()
-              , t = this._texture.getSize();
-            e.clearRect(0, 0, t.width, t.height),
+            const o = this._texture.getContext()
+              , s = this._texture.getSize();
+            o.clearRect(0, 0, s.width, s.height),
             this._texture.update()
         }
     }

+ 131 - 98
src/XBillboardManager.js

@@ -5,23 +5,19 @@ import Pool from "./Pool.js"
 import XBillboard from "./XBillboard.js"
 
 export default class XBillboardManager {
-    constructor(e) {
-        E(this, "billboardMap", new Map);
-        E(this, "sceneManager");
-        E(this, "billboardPool");
-        E(this, "userBackGroundBlob", new Array);
-        E(this, "npcBackGroundBlob", new Array);
-        E(this, "tickObserver");
-        E(this, "tickInterval");
-        E(this, "_updateLoopObserver");
-        this.sceneManager = e,
+    constructor(d) {
+        this.billboardMap = new Map,
+        this.userBackGroundBlob = new Array,
+        this.npcBackGroundBlob = new Array,
+        this._updateLoopObserver = void 0,
+        this.sceneManager = d,
         this.billboardPool = new Pool(this.createBillboardAsset,this.resetBillboardAsset,0,60,this.sceneManager.Scene,!1),
         this.tickInterval = 250;
-        let t = 0;
+        let o = 0;
         this.tickObserver = this.sceneManager.Scene.onAfterRenderObservable.add(()=>{
-            t += 1,
-            t == this.tickInterval && (this.tick(),
-            t = 0)
+            o += 1,
+            o == this.tickInterval && (this.tick(),
+            o = 0)
         }
         ),
         this.launchBillboardStatusLoop()
@@ -29,118 +25,155 @@ export default class XBillboardManager {
     tick() {
         this.billboardPool.clean(0, this.sceneManager.Scene, !1)
     }
-    createBillboardAsset(e, t=!1) {
-        const r = BABYLON.MeshBuilder.CreatePlane("billboard-", {
+    createBillboardAsset(d, o=!1) {
+        const s = BABYLON.MeshBuilder.CreatePlane("billboard-", {
             height: .001,
             width: .001,
             sideOrientation: BABYLON.Mesh.DOUBLESIDE
-        }, e);
-        r.isPickable = !0,
-        r.setEnabled(!1);
-        const n = new BABYLON.DynamicTexture("billboard-tex-",{
-            width: .001 + 1,
-            height: .001 + 1
-        },e,t,BABYLON.Texture.BILINEAR_SAMPLINGMODE);
-        n.hasAlpha = !0;
-        const o = new BABYLON.StandardMaterial("billboard-mat-",e);
-        return o.diffuseTexture = n,
-        o.emissiveColor = new BABYLON.Color3(.95,.95,.95),
-        o.useAlphaFromDiffuseTexture = !0,
-        r.material = o,
-        r.billboardMode = BABYLON.Mesh.BILLBOARDMODE_Y,
-        r.position.y = 0,
-        r
+        }, d);
+        s.isPickable = !0,
+        s.setEnabled(!1);
+        const c = new BABYLON.DynamicTexture("billboard-tex-",{
+            width: 2,
+            height: 2
+        },d,o,BABYLON.Texture.BILINEAR_SAMPLINGMODE);
+        c.hasAlpha = !0;
+        const _ = new BABYLON.StandardMaterial("billboard-mat-",d);
+        return _.diffuseTexture = c,
+        _.emissiveColor = new BABYLON.Color3(.95,.95,.95),
+        _.useAlphaFromDiffuseTexture = !0,
+        s.material = _,
+        s.billboardMode = BABYLON.Mesh.BILLBOARDMODE_Y,
+        s.position.y = 0,
+        s
     }
-    resetBillboardAsset(e) {
-        const t = e.data;
-        return t.setEnabled(!1),
-        t.isPickable = !1,
-        e
+    resetBillboardAsset(d) {
+        const o = d.data;
+        return o.setEnabled(!1),
+        o.isPickable = !1,
+        d
     }
     async loadBackGroundTexToIDB() {
-        XBillboardManager.userBubbleUrls.forEach(r=>{
-            this.sceneManager.urlTransformer(r).then(n=>{
-                this.userBackGroundBlob.push(n)
+        XBillboardManager.userBubbleUrls.forEach(s=>{
+            this.sceneManager.urlTransformer(s).then(c=>{
+                this.userBackGroundBlob.push(c)
             }
             )
         }
         ),
-        XBillboardManager.npcBubbleUrls.forEach(r=>{
-            this.sceneManager.urlTransformer(r).then(n=>{
-                this.npcBackGroundBlob.push(n)
+        XBillboardManager.npcBubbleUrls.forEach(s=>{
+            this.sceneManager.urlTransformer(s).then(c=>{
+                this.npcBackGroundBlob.push(c)
             }
             )
         }
         )
     }
-    addBillboardToMap(e, t) {
-        this.billboardMap.set(e, t)
+    addBillboardToMap(d, o) {
+        this.billboardMap.set(d, o)
     }
-    addBillboard(e, t, r) {
-        let n = this.getBillboard(e);
-        return n || (n = new XBillboard(this,t,r),
-        this.addBillboardToMap(e, n)),
-        n
+    addBillboard(d, o, s) {
+        let c = this.getBillboard(d);
+        if (!c)
+            c = new XBillboard(this,o,s),
+            this.addBillboardToMap(d, c);
+        else {
+            const _ = c;
+            c = new XBillboard(this,o,s),
+            _.setStatus(BillboardStatus.CLEAR),
+            this.addBillboardToMap("old-" + d, _),
+            this.addBillboardToMap(d, c)
+        }
+        return c
     }
-    generateStaticBillboard(e, {id: t="billboard", isUser: r, background: n, font: o="Arial", fontsize: a=40, fontcolor: s="#ffffff", fontstyle: l="600", linesize: u=16, linelimit: c, scale: h=1, width: f=.01, height: d=.01, position: _={
+    generateStaticBillboard(d, {id: o="billboard", isUser: s, background: c, font: _="Arial", fontsize: b=40, fontcolor: k="#ffffff", fontstyle: j="600", linesize: $=16, linelimit: _e, scale: et=1, width: tt=.01, height: rt=.01, position: it={
         x: 0,
         y: 0,
         z: 0
     }}) {
-        const g = this.addBillboard(t, !1, !0);
-        g.getMesh() == null && g.init(t, f, d);
-        let m;
-        r != null && (m = r ? XBillboardManager.userBubbleUrls : XBillboardManager.npcBubbleUrls),
-        g && g.getMesh() && (g.DEFAULT_CONFIGS = {
-            id: t,
-            isUser: r,
-            background: n,
-            font: o,
-            fontsize: a,
-            fontcolor: s,
-            fontstyle: l,
-            linesize: u,
-            linelimit: c,
-            scale: h,
-            width: f,
-            height: d,
-            position: _
+        const nt = this.addBillboard(o, !1, !0);
+        nt.getMesh() == null && nt.init(o, tt, rt);
+        let at;
+        s != null && (at = s ? XBillboardManager.userBubbleUrls : XBillboardManager.npcBubbleUrls),
+        nt && nt.getMesh() && (nt.DEFAULT_CONFIGS = {
+            id: o,
+            isUser: s,
+            background: c,
+            font: _,
+            fontsize: b,
+            fontcolor: k,
+            fontstyle: j,
+            linesize: $,
+            linelimit: _e,
+            scale: et,
+            width: tt,
+            height: rt,
+            position: it
         },
-        g.drawBillboard({
-            imageList: n || m
+        nt.drawBillboard({
+            imageList: c || at
         }, {
-            texts: e,
-            font: o,
-            fontsize: a,
-            fontcolor: s,
-            fontstyle: l,
-            linesize: u,
-            linelimit: c
+            texts: d,
+            font: _,
+            fontsize: b,
+            fontcolor: k,
+            fontstyle: j,
+            linesize: $,
+            linelimit: _e
         }, {
-            position: _,
-            scale: h
+            position: it,
+            scale: et
         }),
-        t && g.setId(t),
-        g.setStatus(BillboardStatus.SHOW))
+        o && nt.setId(o),
+        nt.setStatus(BillboardStatus.SHOW))
     }
-    getBillboard(e) {
-        return this.billboardMap.get(e)
+    getBillboard(d) {
+        return this.billboardMap.get(d)
     }
-    toggle(e, t) {
-        var r;
-        (r = this.getBillboard(e)) == null || r.setStatus(t ? BillboardStatus.SHOW : BillboardStatus.HIDE)
+    toggle(d, o) {
+        var s;
+        (s = this.getBillboard(d)) == null || s.setStatus(o ? BillboardStatus.SHOW : BillboardStatus.HIDE)
     }
-    removeBillboard(e) {
-        const t = this.getBillboard(e);
-        t && (t.setStatus(BillboardStatus.DISPOSE),
-        this.billboardMap.delete(e))
+    clearBillboard(d) {
+        const o = this.getBillboard(d);
+        o == null || o.setStatus(BillboardStatus.CLEAR)
     }
     launchBillboardStatusLoop() {
         this._updateLoopObserver = this.sceneManager.Scene.onBeforeRenderObservable.add(()=>{
-            this.billboardMap.size <= 0 || this.billboardMap.forEach(e=>{
-                e.stageChanged && (e.status == BillboardStatus.SHOW ? e.show() : e.status == BillboardStatus.HIDE ? e.hide() : (e.hide(),
-                e.dispose()),
-                e.stageChanged = !1)
+            if (this.billboardMap.size <= 0)
+                return;
+            const d = new Array;
+            this.billboardMap.forEach((o,s)=>{
+                if (o.stageChanged) {
+                    if (o.status == BillboardStatus.SHOW)
+                        o.show();
+                    else if (o.status == BillboardStatus.HIDE)
+                        o.hide();
+                    else if (o.status == BillboardStatus.DISPOSE) {
+                        const c = o.getMesh();
+                        if (c && o.owner) {
+                            const _ = o.owner._attachmentObservers.get(c);
+                            _ && (this.sceneManager.Scene.onBeforeRenderObservable.remove(_),
+                            o.owner._attachmentObservers.delete(c))
+                        }
+                        o.hide(),
+                        o.dispose()
+                    } else if (o.status == BillboardStatus.CLEAR) {
+                        const c = o.getMesh();
+                        if (c && o.owner) {
+                            const _ = o.owner._attachmentObservers.get(c);
+                            _ && (this.sceneManager.Scene.onBeforeRenderObservable.remove(_),
+                            o.owner._attachmentObservers.delete(c))
+                        }
+                        d.push(s),
+                        o == null || o.dispose()
+                    }
+                    o.stageChanged = !1
+                }
+            }
+            ),
+            d.forEach(o=>{
+                this.billboardMap.delete(o)
             }
             )
         }
@@ -149,6 +182,6 @@ export default class XBillboardManager {
 }
 ;
 
-E(XBillboardManager, "alphaWidthMap", new Map),
-E(XBillboardManager, "userBubbleUrls", [texRootDir + "bubble01.png", texRootDir + "bubble02.png", texRootDir + "bubble03.png"]),
-E(XBillboardManager, "npcBubbleUrls", [texRootDir + "bubble01_npc.png", texRootDir + "bubble02_npc.png", texRootDir + "bubble03_npc.png"]);
+XBillboardManager.alphaWidthMap = new Map;
+XBillboardManager.userBubbleUrls = [texRootDir + "bubble01.png", texRootDir + "bubble02.png", texRootDir + "bubble03.png"];
+XBillboardManager.npcBubbleUrls = [texRootDir + "bubble01_npc.png", texRootDir + "bubble02_npc.png", texRootDir + "bubble03_npc.png"];

+ 212 - 274
src/XBreathPointManager.js

@@ -1,6 +1,6 @@
 import XStaticMesh from "./XStaticMesh.js"
 import EMeshType from "./enum/EMeshType.js"
-import BreathPoint from "./BreathPoint.js"
+import Marker from "./Marker.js"
 import Logger from "./Logger.js"
 import XBreathPointError from "./Error/XBreathPointError.js"
 
@@ -9,344 +9,282 @@ const pointsArr2 = [61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
 const pointsArr3 = [106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226]
 const pointsArr4 = [133,134,135,136,137,138,139,140,141,142,143,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286]
 
-const logger = new Logger('BreathPointManager')
+const logger = new Logger('XBreathPointManager')
 export default class XBreathPointManager {
-    constructor(e) {
-        E(this, "_scene");
-        E(this, "materialMap", new Map);
-        E(this, "breathPoints", new Map);
-        E(this, "_sceneManager");
-        E(this, "_allIds", new Set);
-        E(this, "_loopBPKeys", []);
-        E(this, "addBreathPoint", async info=>{
-            const t = [{
-                // url: "https://static.xverse.cn/qqktv/texture.png"
-                url: "./assets/textures/breathPoint/texture.png"
-            },{
-                url: "./assets/textures/breathPoint/texture_yellow.png"
-            },{
-                url: "./assets/textures/breathPoint/texture_purple.png"
-            },{
-                url: "./assets/textures/breathPoint/texture_green.png",
+    constructor(o) {
+        this.materialMap = new Map,
+        this.breathPoints = new Map,
+        this._allIds = new Set,
+        this._loopBPKeys = [],
+        this.addBreathPoint = async s=>{
+            const c = [{
+                url: "https://static.xverse.cn/qqktv/texture.png"
             }];
-            if (t.length <= 0) {
+            if (c.length <= 0) {
                 logger.warn("[Engine] BreathPoint get texture list error: textureList.length <= 0"),
                 new XBreathPointError("[Engine] BreathPoint get texture list error!");
                 return
             }
-            let r = t[1]
-            let {
-                id, spriteSheet=r.url, spriteWidthNumber=20, spriteHeightNumber=1, position, rotation={ pitch: -90, yaw: 270, roll: 0 }, 
-                size=.6, width=-1, height=-1, fps=30, billboardMode=!1, forceLeaveGround=!1, type="default", lifeTime=-1, backfaceculling=!0, 
-                maxVisibleRegion=-1, skinInfo="default"
-            } = info;
-
-            if (this.breathPoints.get(id)) {
-                logger.warn("[Engine] Cannot add breathPoint with an existing id: [" + id + "]"),
-                new XBreathPointError("[Engine] Cannot add breathPoint with an existing id: [" + id + "]");
+            const _ = c[0]
+              , {id: b, spriteSheet: k=_.url, spriteWidthNumber: j=20, spriteHeightNumber: $=1, position: _e, rotation: et={
+                pitch: -90,
+                yaw: 270,
+                roll: 0
+            }, size: tt=.6, width: rt=-1, height: it=-1, fps: nt=30, billboardMode: at=!1, forceLeaveGround: ot=!1, type: st="default", lifeTime: lt=-1, backfaceculling: ut=!0, maxVisibleRegion: ct=-1, skinInfo: ht="default"} = s;
+            if (this.breathPoints.get(b)) {
+                logger.warn("[Engine] Cannot add breathPoint with an existing id: [" + b + "]"),
+                new XBreathPointError("[Engine] Cannot add breathPoint with an existing id: [" + b + "]");
                 return
             }
-            if (forceLeaveGround) {
-                const I = this.castRay(new BABYLON.Vector3(position.x, position.y, position.z)) * scaleFromUE4toXverse;
-                I != 0 ? position.z = position.z - I + 1 : position.z = position.z + 1
+            if (ot) {
+                const vt = this.castRay(new BABYLON.Vector3(_e.x,_e.y,_e.z)) * scaleFromUE4toXverse;
+                vt != 0 ? _e.z = _e.z - vt + 1 : _e.z = _e.z + 1
             }
-
-            if(pointsArr1.indexOf(parseInt(id)) > -1) type = "p1"
-            if(pointsArr2.indexOf(parseInt(id)) > -1) type = "p2"
-            if(pointsArr3.indexOf(parseInt(id)) > -1) type = "p3"
-
-            let mat;
-            if (this.materialMap.get(type)) {
-                const I = this.materialMap.get(type);
-                I.count = I.count + 1,
-                mat = I.mat
+            let dt;
+            if (this.materialMap.get(st)) {
+                const vt = this.materialMap.get(st);
+                vt.count = vt.count + 1,
+                dt = vt.mat
             } else {
-                const texture = new BABYLON.Texture(spriteSheet, this._scene, !0, !0, BABYLON.Texture.BILINEAR_SAMPLINGMODE, null, ()=>{
+                const vt = new BABYLON.Texture(k,this._scene,!0,!0,BABYLON.Texture.BILINEAR_SAMPLINGMODE,null,()=>{
                     logger.error("[Engine] Breathpoint create texture error."),
                     new XBreathPointError("[Engine] Breathpoint create texture error.")
-                } ,null, !0);
-                texture.name = "TexBreathPoint_" + id,
-
-                mat = new BABYLON.StandardMaterial(`MaterialBreathPoint_${id}`,this._scene)
-                // todo 暂改
-                // mat.alpha = 1,
-                // mat.emissiveTexture = texture,
-                // mat.backFaceCulling = backfaceculling,
-                // mat.diffuseTexture = texture,
-                // mat.diffuseTexture.hasAlpha = !0,
-                // mat.useAlphaFromDiffuseTexture = !0,
-                if(type == "p1") mat.emissiveColor.set(1,1,1)
-                else if(type == "p2") mat.emissiveColor.set(1,1,0.5)
-                else if(type == "p3") mat.emissiveColor.set(1,0.5,0)
-                else mat.emissiveColor.set(1,0,0)
-
-                this.materialMap.set(type, {
-                    mat,
+                }
+                ,null,!0);
+                vt.name = "TexBreathPoint_" + b,
+                dt = new BABYLON.StandardMaterial(`MaterialBreathPoint_${b}`,this._scene),
+                dt.alpha = 1,
+                dt.emissiveTexture = vt,
+                dt.backFaceCulling = ut,
+                dt.diffuseTexture = vt,
+                dt.diffuseTexture.hasAlpha = !0,
+                dt.useAlphaFromDiffuseTexture = !0,
+                this.materialMap.set(st, {
+                    mat: dt,
                     count: 1,
                     lastRenderTime: Date.now(),
-                    fps,
-                    spriteWidthNumber,
-                    spriteHeightNumber,
-                    spriteSheet,
-                    texture
+                    fps: nt,
+                    spriteWidthNumber: j,
+                    spriteHeightNumber: $,
+                    spriteSheet: k,
+                    texture: vt
                 })
             }
-
-            const faceUV = new Array(6);
-            for (let i = 0; i < 6; i++) faceUV[i] = new BABYLON.Vector4(0,0,0,0);
-            faceUV[0] = new BABYLON.Vector4(0, 0, 1 / spriteWidthNumber, 1 / spriteHeightNumber),
-            faceUV[1] = new BABYLON.Vector4(0, 0, 1 / spriteWidthNumber, 1 / spriteHeightNumber);
-
-            let options = {};
-            width > 0 && height > 0 ? options = {
-                width: width,
-                height: height,
+            const ft = new Array(6);
+            for (let vt = 0; vt < 6; vt++)
+                ft[vt] = new BABYLON.Vector4(0,0,0,0);
+            ft[0] = new BABYLON.Vector4(0,0,1 / j,1 / $),
+            ft[1] = new BABYLON.Vector4(0,0,1 / j,1 / $);
+            let pt = {};
+            rt > 0 && it > 0 ? pt = {
+                width: rt,
+                height: it,
                 depth: .01,
-                faceUV
-            } : options = {
-                size: size/2,   // todo 暂改size
+                faceUV: ft
+            } : pt = {
+                size: tt,
                 depth: .01,
-                faceUV
+                faceUV: ft
             };
-
-            const mesh = BABYLON.MeshBuilder.CreateBox(id, options, this._scene);
-            mesh.material = mat;
-            const xMesh = new XStaticMesh({
-                id,
-                mesh,
+            const gt = BABYLON.MeshBuilder.CreateBox(b, pt, this._scene);
+            gt.material = dt;
+            const _t = new XStaticMesh({
+                id: b,
+                mesh: gt,
                 xtype: EMeshType.XBreathPoint,
-                skinInfo
+                skinInfo: ht
             });
-            
-            let rota = rotation;
-            billboardMode && (
-                mesh.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL,
-                xMesh.allowMove(),
-                rota = {
-                    pitch: 0,
-                    yaw: 270,
-                    roll: 0
-                }
-            );
-            const breathPoint = new BreathPoint({
-                type,
-                mesh: xMesh,
-                id,
-                position,
-                rotation: rota,
-                mat,
-                maxVisibleRegion,
+            let mt = et;
+            at && (gt.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL,
+            _t.allowMove(),
+            mt = {
+                pitch: 0,
+                yaw: 270,
+                roll: 0
+            });
+            const At = new Marker({
+                type: st,
+                mesh: _t,
+                id: b,
+                position: _e,
+                rotation: mt,
+                mat: dt,
+                maxVisibleRegion: ct,
                 scene: this._scene,
-                skinInfo
+                skinInfo: ht
             });
-            this.breathPoints.set(id, breathPoint),
-            this._allIds.add(id),
-            lifeTime > 0 && setTimeout(()=>{
-                this.clearBreathPoints(id)
-            }, lifeTime * 1e3)
-
-            
-
-            if(debugMode) {
-                var textureBPNum = new BABYLON.DynamicTexture("dynamic_texture_" + id, {width:300, height:150}, this._scene);  
-                textureBPNum.drawText(id, 0, 150, "bold 200px monospace", "white", "", true, true); 
-                var materialBPNum = new BABYLON.StandardMaterial("MatBPNum_" + id, this._scene);
-                materialBPNum.diffuseTexture = textureBPNum;
-                materialBPNum.emissiveTexture = textureBPNum;
-                materialBPNum.diffuseTexture.hasAlpha = !0
-                materialBPNum.useAlphaFromDiffuseTexture = !0
-                materialBPNum.zOffset = -4
-
-                var bpNumMesh
-                if(this.bpNumMesh) {
-                    bpNumMesh = this.bpNumMesh.clone("BreathPointNum_" + id)
-                } else {
-                    bpNumMesh = BABYLON.MeshBuilder.CreatePlane("BreathPointNum_" + id, {width: 0.4, height: 0.2, subdivisions: 1}, this._scene);
-                    bpNumMesh.rotation = new BABYLON.Vector3(Math.PI / 2, 0, 0)
-                    this.bpNumMesh = bpNumMesh
-                }
-                bpNumMesh.position = mesh.position
-                bpNumMesh.material = materialBPNum;
-
-                // let standardVec = BABYLON.Vector3.Project(
-                //     mesh.position, 
-                //     BABYLON.Matrix.Identity(),
-                //     this._scene.getViewMatrix(),
-                //     this._scene.getProjectionMatrix()
-                // )
-                // console.error(standardVec)
-                // let screenX = Math.round(window.innerWidth / 2 * standardVec.x + window.innerWidth / 2)
-                // let screenY = Math.round(window.innerHeight / 2 * standardVec.y + window.innerHeight / 2)
-                // let idContant = document.createElement("div")
-                // idContant.innerHTML = id
-                // idContant.style.position = "absolute"
-                // idContant.style.top = screenY + "px"
-                // idContant.style.left = screenX + "px"
-                // document.querySelector("#root").appendChild(idContant)
+            this.breathPoints.set(b, At),
+            this._allIds.add(b),
+            lt > 0 && setTimeout(()=>{
+                this.clearBreathPoints(b)
             }
-        
-        });
-
-        E(this, "reg_breathpoint_update", ()=>{
-            const e = new Date().getTime();
+            , lt * 1e3),
+            GEngine.engineOption.bDisableLocalRender ? At.toggleVisibility(!1) : At.toggleVisibility(!0)
+        }
+        ,
+        this.reg_breathpoint_update = ()=>{
+            const s = new Date().getTime();
             if (this.materialMap != null)
-                for (const [t,r] of this.materialMap)
-                    e - r.lastRenderTime > 1e3 / r.fps && (r.lastRenderTime = e,
-                    Math.abs(r.mat.diffuseTexture.uOffset - (1 - 1 / r.spriteWidthNumber)) < 1e-6 ? (r.mat.diffuseTexture.uOffset = 0,
-                    Math.abs(r.mat.diffuseTexture.vOffset - (1 - 1 / r.spriteHeightNumber)) < 1e-6 ? r.mat.diffuseTexture.vOffset = 0 : r.mat.diffuseTexture.vOffset += 1 / r.spriteHeightNumber) : r.mat.diffuseTexture.uOffset += 1 / r.spriteWidthNumber)
+                for (const [c,_] of this.materialMap)
+                    s - _.lastRenderTime > 1e3 / _.fps && (_.lastRenderTime = s,
+                    Math.abs(_.mat.diffuseTexture.uOffset - (1 - 1 / _.spriteWidthNumber)) < 1e-6 ? (_.mat.diffuseTexture.uOffset = 0,
+                    Math.abs(_.mat.diffuseTexture.vOffset - (1 - 1 / _.spriteHeightNumber)) < 1e-6 ? _.mat.diffuseTexture.vOffset = 0 : _.mat.diffuseTexture.vOffset += 1 / _.spriteHeightNumber) : _.mat.diffuseTexture.uOffset += 1 / _.spriteWidthNumber)
         }
-        );
-        E(this, "reg_breathpoint_autovisible", ()=>{
+        ,
+        this.reg_breathpoint_autovisible = ()=>{
             if (this._scene.getFrameId() % 2 == 0)
                 if (this._loopBPKeys.length == 0)
                     this._loopBPKeys = Array.from(this._allIds);
                 else {
-                    const e = this._getMainPlayerPosition();
-                    for (let t = 0; t < 5 && this._loopBPKeys.length > 0; ++t) {
-                        const r = this._loopBPKeys.pop();
-                        if (r != null) {
-                            const n = this.getBreathPoint(r);
-                            if (n != null && n.maxvisibleregion >= 0 && n.mesh.visibility == 1) {
-                                const o = n.mesh.position;
-                                calcDistance3DVector(e, o) >= n.maxvisibleregion ? n == null || n.removeFromScene() : n == null || n.addToScene()
+                    const s = this._getMainPlayerPosition();
+                    for (let c = 0; c < 5 && this._loopBPKeys.length > 0; ++c) {
+                        const _ = this._loopBPKeys.pop();
+                        if (_ != null) {
+                            const b = this.getBreathPoint(_);
+                            if (b != null && b.maxvisibleregion >= 0 && b.mesh.visibility == 1) {
+                                const k = b.mesh.position;
+                                calcDistance3DVector(s, k) >= b.maxvisibleregion ? b == null || b.removeFromScene() : b == null || b.addToScene()
                             }
                         }
                     }
                 }
         }
-        );
-        this._sceneManager = e,
-        this._scene = e.Scene,
-        // todo 暂改
-        // this._scene.registerBeforeRender(this.reg_breathpoint_update),
+        ,
+        this._sceneManager = o,
+        this._scene = o.Scene,
+        this._scene.registerBeforeRender(this.reg_breathpoint_update),
         this._scene.registerBeforeRender(this.reg_breathpoint_autovisible)
     }
-    setAllBreathPointVisibility(e) {
-        for (const [t,r] of this.breathPoints.entries())
-            r.toggleVisibility(e)
+    setAllBreathPointVisibility(o) {
+        for (const [s,c] of this.breathPoints.entries())
+            c.toggleVisibility(o)
     }
-    toggleBPVisibilityBySkinInfo(e, t) {
-        for (const [r,n] of this.breathPoints.entries())
-            n.skinInfo == e && n.toggleVisibility(t)
+    toggleBPVisibilityBySkinInfo(o, s) {
+        for (const [c,_] of this.breathPoints.entries())
+            _.skinInfo == o && _.toggleVisibility(s)
     }
-    toggleBPVisibilityById(e, t) {
-        const r = this.getBreathPoint(e);
-        r != null && r.toggleVisibility(t)
+    toggleBPVisibilityById(o, s) {
+        const c = this.getBreathPoint(o);
+        c != null && c.toggleVisibility(s)
     }
-    getBreathPointBySkinInfo(e) {
-        const t = [];
-        for (const [r,n] of this.breathPoints.entries())
-            n.skinInfo == e && t.push(n);
-        return t
+    getBreathPointBySkinInfo(o) {
+        const s = [];
+        for (const [c,_] of this.breathPoints.entries())
+            _.skinInfo == o && s.push(_);
+        return s
     }
     getAllBreathPoint() {
         return this.breathPoints
     }
-    getBreathPoint(e) {
-        return this.breathPoints.get(e)
+    getBreathPoint(o) {
+        return this.breathPoints.get(o)
     }
-    delete(e) {
-        const t = this.breathPoints.get(e);
-        if (t != null) {
-            t.dispose(),
-            this._allIds.delete(e);
-            const r = this.materialMap.get(t._type);
-            r != null && (r.count = r.count - 1,
-            r.count <= 0 && (r.count = 0,
-            r.texture.dispose(),
-            r.mat.dispose(!0, !0),
-            this.materialMap.delete(t._type))),
-            this.breathPoints.delete(e)
+    delete(o) {
+        const s = this.breathPoints.get(o);
+        if (s != null) {
+            s.dispose(),
+            this._allIds.delete(o);
+            const c = this.materialMap.get(s._type);
+            c != null && (c.count = c.count - 1,
+            c.count <= 0 && (c.count = 0,
+            c.texture.dispose(),
+            c.mat.dispose(!0, !0),
+            this.materialMap.delete(s._type))),
+            this.breathPoints.delete(o)
         }
     }
-    castRay(e) {
-        var s;
-        e = ue4Position2Xverse({
-            x: e.x,
-            y: e.y,
-            z: e.z
+    castRay(o) {
+        var j;
+        o = ue4Position2Xverse({
+            x: o.x,
+            y: o.y,
+            z: o.z
         });
-        const t = new BABYLON.Vector3(0,-1,0)
-          , r = new BABYLON.Ray(e,t,length)
-          , n = []
-          , o = (s = this._sceneManager) == null ? void 0 : s.getGround({
-            x: e.x,
-            y: e.y,
-            z: e.z
+        const s = new BABYLON.Vector3(0,-1,0)
+          , c = new BABYLON.Ray(o,s,length)
+          , _ = []
+          , b = (j = this._sceneManager) == null ? void 0 : j.getGround({
+            x: o.x,
+            y: o.y,
+            z: o.z
         });
-        let a = r.intersectsMeshes(o);
-        if (a.length > 0) {
-            const l = a[0];
-            if (l && l.pickedMesh) {
-                const u = l.distance;
-                t.y = 1;
-                const c = r.intersectsMeshes(n);
-                let h = 1e8;
-                if (c.length > 0) {
-                    const f = c[0];
-                    return f && f.pickedMesh && (h = -f.distance),
-                    h == 1e8 ? u : Math.abs(h) < Math.abs(u) ? h : u
+        let k = c.intersectsMeshes(b);
+        if (k.length > 0) {
+            const $ = k[0];
+            if ($ && $.pickedMesh) {
+                const _e = $.distance;
+                s.y = 1;
+                const et = c.intersectsMeshes(_);
+                let tt = 1e8;
+                if (et.length > 0) {
+                    const rt = et[0];
+                    return rt && rt.pickedMesh && (tt = -rt.distance),
+                    tt == 1e8 ? _e : Math.abs(tt) < Math.abs(_e) ? tt : _e
                 }
             }
-        } else if (t.y = 1,
-        a = r.intersectsMeshes(n),
-        a.length > 0) {
-            const l = a[0];
-            if (l && l.pickedMesh)
-                return l.distance
+        } else if (s.y = 1,
+        k = c.intersectsMeshes(_),
+        k.length > 0) {
+            const $ = k[0];
+            if ($ && $.pickedMesh)
+                return $.distance
         }
         return 0
     }
-    changePickable(e) {
-        for (const [t,r] of this.breathPoints.entries())
-            r.changePickable(e)
+    changePickable(o) {
+        for (const [s,c] of this.breathPoints.entries())
+            c.changePickable(o)
     }
-    clearBreathPoints(e) {
-        logger.info(`[Engine] clearBreathPoints: ${e}`);
-        for (const [t,r] of this.breathPoints.entries())
-            (r._type == e || r._id == e) && this.delete(r._id)
+    clearBreathPoints(o) {
+        logger.info(`[Engine] clearBreathPoints: ${o}`);
+        for (const [s,c] of this.breathPoints.entries())
+            (c._type == o || c._id == o) && this.delete(c._id)
     }
-    clearBreathPointsBySkinInfo(e) {
-        logger.info(`[Engine] clearBreathPointsBySkinInfo: ${e}`);
-        for (const [t,r] of this.breathPoints.entries())
-            r.skinInfo == e && this.delete(r._id)
+    clearBreathPointsBySkinInfo(o) {
+        logger.info(`[Engine] clearBreathPointsBySkinInfo: ${o}`);
+        for (const [s,c] of this.breathPoints.entries())
+            c.skinInfo == o && this.delete(c._id)
     }
     clearAllBreathPoints() {
         logger.info("[Engine] ClearAllBreathPoints");
-        for (const [e,t] of this.breathPoints.entries())
-            this.delete(t._id)
+        for (const [o,s] of this.breathPoints.entries())
+            this.delete(s._id)
     }
     _getMainPlayerPosition() {
-        var r;
-        const e = this._sceneManager.cameraComponent.MainCamera.position
-          , t = this._sceneManager.avatarComponent.getMainAvatar();
-        if (t != null && t != null) {
-            const n = (r = t == null ? void 0 : t.rootNode) == null ? void 0 : r.position;
-            if (n != null)
-                return n
+        var c;
+        const o = this._sceneManager.cameraComponent.MainCamera.position
+          , s = this._sceneManager.avatarComponent.getMainAvatar();
+        if (s != null && s != null) {
+            const _ = (c = s == null ? void 0 : s.rootNode) == null ? void 0 : c.position;
+            if (_ != null)
+                return _
         }
-        return e
+        return o
     }
-    changeBreathPointPose(e, t, r) {
-        const n = new BABYLON.Vector3(e.position.x,e.position.y,e.position.z);
-        if (this.breathPoints.get(r) != null) {
-            logger.info(`[Engine] changeBreathPointPose, id:${r}`);
-            const o = this.breathPoints.get(r)
-              , a = o.mesh.position;
-            let s = a.subtract(n);
-            s = BABYLON.Vector3.Normalize(s);
-            const l = BABYLON.Vector3.Distance(a, n)
-              , u = new Ray(n,s,l)
-              , c = this._scene.multiPickWithRay(u);
-            if (c) {
-                for (let h = 0; h < c.length; h++)
-                    if (c[h].pickedMesh != null && t.mesh.name.indexOf(c[h].pickedMesh.name) >= 0) {
-                        const f = c[h].pickedPoint;
-                        o.mesh.position = n.add(f.subtract(n).scale(.99)),
-                        this.breathPoints.set(r, o)
+    changeBreathPointPose(o, s, c) {
+        const _ = new BABYLON.Vector3(o.position.x,o.position.y,o.position.z);
+        if (this.breathPoints.get(c) != null) {
+            logger.info(`[Engine] changeBreathPointPose, id:${c}`);
+            const b = this.breathPoints.get(c)
+              , k = b.mesh.position;
+            let j = k.subtract(_);
+            j = BABYLON.Vector3.Normalize(j);
+            const $ = BABYLON.Vector3.Distance(k, _)
+              , _e = new BABYLON.Ray(_,j,$)
+              , et = this._scene.multiPickWithRay(_e);
+            if (et) {
+                for (let tt = 0; tt < et.length; tt++)
+                    if (et[tt].pickedMesh != null) {
+                        let rt = "";
+                        if (s instanceof XStaticMesh ? rt = s.mesh.name : rt = s.name,
+                        rt.indexOf(et[tt].pickedMesh.name) >= 0) {
+                            const it = et[tt].pickedPoint;
+                            b.mesh.position = _.add(it.subtract(_).scale(.9)),
+                            this.breathPoints.set(c, b)
+                        }
                     }
             }
         } else
-            logger.warn(`[Engine] changeBreathPointPose, id:${r} is not existing!`)
+            logger.warn(`[Engine] changeBreathPointPose, id:${c} is not existing!`)
     }
 }

+ 253 - 196
src/XCameraComponent.js

@@ -1,158 +1,162 @@
 export default class XCameraComponent {
-    constructor(canvas, scene, r) {
-        this.maincameraRotLimitObserver = null
-        this.mainCamera
-        this.cgCamera
-        this.saveCameraPose
-        this._cameraPose
-        this.forceKeepVertical = !1
-
-        this.scene = scene,
-        this.canvas = canvas,
-        this.yuvInfo = r.yuvInfo,
-        r.forceKeepVertical != null && (this.forceKeepVertical = r.forceKeepVertical),
-        this.initCamera(r.cameraParam)
-    }
-    
-    initCamera = cameraParam=>{
-        const {maxZ: t=1e4, minZ: r=.1, angularSensibility: n=2e3} = cameraParam;
-        this.mainCamera = new BABYLON.FreeCamera("camera_main",new BABYLON.Vector3(0,0,1),this.scene),
-        this.mainCamera.mode = BABYLON.Camera.PERSPECTIVE_CAMERA,
-        this.mainCamera.speed = .1,
-        this.mainCamera.angularSensibility = n,
-        this.mainCamera.setTarget(new BABYLON.Vector3(0,0,0)),
-        this.mainCamera.minZ = r,
-        this.mainCamera.fov = Math.PI * this.yuvInfo.fov / 180,
-        this.mainCamera.maxZ = t,
-        this.mainCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
-        this.cgCamera = new BABYLON.FreeCamera("camera_temp",new BABYLON.Vector3(0,1e3,0),this.scene),
-        this.cgCamera.mode = BABYLON.Camera.PERSPECTIVE_CAMERA,
-        this.cgCamera.speed = .1,
-        this.cgCamera.setTarget(new BABYLON.Vector3(0,1010,0)),
-        this.cgCamera.maxZ = t,
-        this.cgCamera.minZ = r,
-        this.cgCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
-        this.cameraFovChange(this.yuvInfo)
-    }
-    cameraFovChange = e=>{
-        this.yuvInfo = e;
-        const t = e.width
-          , r = e.height
-          , n = this.canvas.width
-          , o = this.canvas.height
-          , a = e.fov;
-        if (this.forceKeepVertical == !0) {
-            const s = t / (2 * Math.tan(Math.PI * a / 360))
-              , l = 2 * Math.atan(r / (2 * s));
-            this.mainCamera.fov = l,
-            this.cgCamera.fov = l,
-            this.mainCamera.fovMode = BABYLON.Camera.FOVMODE_VERTICAL_FIXED,
-            this.cgCamera.fovMode = BABYLON.Camera.FOVMODE_VERTICAL_FIXED
-        } else if (this.mainCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
-        this.cgCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
-        n / o < t / r && this.mainCamera.fov) {
-            const s = o
-              , l = n
-              , u = s * t / r / (2 * Math.tan(a * Math.PI / 360))
-              , c = 2 * Math.atan(l / (2 * u));
-            this.mainCamera.fov = c,
-            this.cgCamera.fov = c
-        } else
-            this.mainCamera.fov = Math.PI * a / 180,
-            this.cgCamera.fov = Math.PI * a / 180
-    }
-    setCameraPose = e=>{
-        var n;
-        const t = ue4Position2Xverse(e.position);
-        let r = null;
-        e.rotation != null && (r = ue4Rotation2Xverse(e.rotation)),
-        this._cameraPose = {
-            position: t
-        },
-        r != null && (this._cameraPose.rotation = r),
-        this.scene.activeCamera === this.mainCamera && !((n = this.mainCamera) != null && n.isDisposed()) && this._setCamPositionRotation(this.mainCamera, this._cameraPose)
-    }
-    _setCamPositionRotation = (e,t)=>{
-        var r, n;
-        t.position && (e.position = (r = t.position) == null ? void 0 : r.clone()),
-        t.rotation && (e.rotation = (n = t.rotation) == null ? void 0 : n.clone())
-    }
-    switchCamera = e=>{
-        var t;
-        (t = this.scene.activeCamera) == null || t.detachControl(this.canvas),
-        this.scene.activeCamera = e
-    }
-    reCalXYZRot = (e,t)=>(
-        e = e % (2 * Math.PI),
-        Math.abs(t - e) >= Math.PI && (e = e - 2 * Math.PI),
-        e
-    )
-    _moveCam = (e,t,r,n,o,a,s,l)=>{
-        const u = (v,y,b)=>(v.x = this.reCalXYZRot(v.x, y.x),
-        v.y = this.reCalXYZRot(v.y, y.y),
-        v.z = this.reCalXYZRot(v.z, y.z),
-        new BABYLON.Vector3((y.x - v.x) * b + v.x,(y.y - v.y) * b + v.y,(y.z - v.z) * b + v.z))
-          , c = function(v, y, b) {
-            return new BABYLON.Vector3((y.x - v.x) * b + v.x,(y.y - v.y) * b + v.y,(y.z - v.z) * b + v.z)
+    constructor(o, s, c) {
+        this.maincameraRotLimitObserver = null,
+        this._cameraFixRate = 1,
+        this.forceKeepVertical = !1,
+        this.initCamera = _=>{
+            const {maxZ: b=1e4, minZ: k=.1, angularSensibility: j=2e3} = _;
+            this.mainCamera = new BABYLON.FreeCamera("camera_main",new BABYLON.Vector3(0,1e3,0),this.scene),
+            this.mainCamera.mode = BABYLON.Camera.PERSPECTIVE_CAMERA,
+            this.mainCamera.speed = .1,
+            this.mainCamera.angularSensibility = j,
+            this.mainCamera.setTarget(new BABYLON.Vector3(0,1010,0)),
+            this.mainCamera.minZ = k,
+            this.mainCamera.fov = Math.PI * this.yuvInfo.fov / 180,
+            this.mainCamera.maxZ = b,
+            this.mainCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
+            this.cgCamera = new BABYLON.FreeCamera("camera_temp",new BABYLON.Vector3(0,1e3,0),this.scene),
+            this.cgCamera.mode = BABYLON.Camera.PERSPECTIVE_CAMERA,
+            this.cgCamera.speed = .1,
+            this.cgCamera.setTarget(new BABYLON.Vector3(0,1010,0)),
+            this.cgCamera.maxZ = b,
+            this.cgCamera.minZ = k,
+            this.cgCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
+            this.cameraFovChange(this.yuvInfo)
+        }
+        ,
+        this.cameraFovChange = _=>{
+            this.yuvInfo = _;
+            const b = _.width
+              , k = _.height
+              , j = this.canvas.width
+              , $ = this.canvas.height
+              , _e = _.fov;
+            if (this.forceKeepVertical == !0) {
+                const et = b / (2 * Math.tan(Math.PI * _e / 360))
+                  , tt = 2 * Math.atan(k / (2 * et));
+                this.mainCamera.fov = tt,
+                this.cgCamera.fov = tt,
+                this.mainCamera.fovMode = BABYLON.Camera.FOVMODE_VERTICAL_FIXED,
+                this.cgCamera.fovMode = BABYLON.Camera.FOVMODE_VERTICAL_FIXED
+            } else if (this.mainCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
+            this.cgCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED,
+            j / $ < b / k && this.mainCamera.fov) {
+                const et = $
+                  , tt = j
+                  , rt = et * b / k / (2 * Math.tan(_e * Math.PI / 360))
+                  , it = 2 * Math.atan(tt / (2 * rt));
+                this.mainCamera.fov = it,
+                this.cgCamera.fov = it
+            } else
+                this.mainCamera.fov = Math.PI * _e / 180,
+                this.cgCamera.fov = Math.PI * _e / 180
+        }
+        ,
+        this.setCameraPose = _=>{
+            var j;
+            const b = ue4Position2Xverse(_.position);
+            let k = null;
+            _.rotation != null && (k = ue4Rotation2Xverse(_.rotation)),
+            this._cameraPose = {
+                position: b
+            },
+            k != null && (this._cameraPose.rotation = k),
+            this.scene.activeCamera === this.mainCamera && !((j = this.mainCamera) != null && j.isDisposed()) && this._setCamPositionRotation(this.mainCamera, this._cameraPose)
+        }
+        ,
+        this._setCamPositionRotation = (_,b)=>{
+            var k, j;
+            b.position && (_.position = (k = b.position) == null ? void 0 : k.clone()),
+            b.rotation && (_.rotation = (j = b.rotation) == null ? void 0 : j.clone())
         }
-          , h = new Animation("myAnimation1","position",s,Animation.ANIMATIONTYPE_VECTOR3,Animation.ANIMATIONLOOPMODE_CONSTANT);
-        let f = []
-          , d = t
-          , _ = r;
-        for (let v = 0; v < a; ++v)
-            f.push({
-                frame: v,
-                value: c(d, _, v / a)
-            });
-        f.push({
-            frame: f.length,
-            value: c(d, _, 1)
-        }),
-        h.setKeys(f);
-        const g = new Animation("myAnimation2","rotation",s,Animation.ANIMATIONTYPE_VECTOR3,Animation.ANIMATIONLOOPMODE_CONSTANT);
-        f = [],
-        d = n,
-        _ = o;
-        for (let v = 0; v < a; ++v)
-            f.push({
-                frame: v,
-                value: u(d, _, v / a)
-            });
-        f.push({
-            frame: f.length,
-            value: u(d, _, 1)
-        }),
-        g.setKeys(f),
-        e.animations.push(g),
-        e.animations.push(h);
-        const m = this.scene.beginAnimation(e, 0, a, !1);
-        m.onAnimationEnd = ()=>{
-            l(),
-            m.stop(),
-            m.animationStarted = !1
+        ,
+        this.switchCamera = _=>{
+            var b;
+            (b = this.scene.activeCamera) == null || b.detachControl(this.canvas),
+            this.scene.activeCamera = _
         }
+        ,
+        this.reCalXYZRot = (_,b)=>(_ = _ % (2 * Math.PI),
+        Math.abs(b - _) >= Math.PI && (_ = _ - 2 * Math.PI),
+        _),
+        this._moveCam = (_,b,k,j,$,_e,et,tt)=>{
+            const rt = (ct,ht,dt)=>(ct.x = this.reCalXYZRot(ct.x, ht.x),
+            ct.y = this.reCalXYZRot(ct.y, ht.y),
+            ct.z = this.reCalXYZRot(ct.z, ht.z),
+            new BABYLON.Vector3((ht.x - ct.x) * dt + ct.x,(ht.y - ct.y) * dt + ct.y,(ht.z - ct.z) * dt + ct.z))
+              , it = function(ct, ht, dt) {
+                return new BABYLON.Vector3((ht.x - ct.x) * dt + ct.x,(ht.y - ct.y) * dt + ct.y,(ht.z - ct.z) * dt + ct.z)
+            }
+              , nt = new Animation("myAnimation1","position",et,Animation.ANIMATIONTYPE_VECTOR3,Animation.ANIMATIONLOOPMODE_CONSTANT);
+            let at = []
+              , ot = b
+              , st = k;
+            for (let ct = 0; ct < _e; ++ct)
+                at.push({
+                    frame: ct,
+                    value: it(ot, st, ct / _e)
+                });
+            at.push({
+                frame: at.length,
+                value: it(ot, st, 1)
+            }),
+            nt.setKeys(at);
+            const lt = new Animation("myAnimation2","rotation",et,Animation.ANIMATIONTYPE_VECTOR3,Animation.ANIMATIONLOOPMODE_CONSTANT);
+            at = [],
+            ot = j,
+            st = $;
+            for (let ct = 0; ct < _e; ++ct)
+                at.push({
+                    frame: ct,
+                    value: rt(ot, st, ct / _e)
+                });
+            at.push({
+                frame: at.length,
+                value: rt(ot, st, 1)
+            }),
+            lt.setKeys(at),
+            _.animations.push(lt),
+            _.animations.push(nt);
+            const ut = this.scene.beginAnimation(_, 0, _e, !1);
+            ut.onAnimationEnd = ()=>{
+                tt(),
+                ut.stop(),
+                ut.animationStarted = !1
+            }
+        }
+        ,
+        this.scene = s,
+        this.canvas = o,
+        this.yuvInfo = c.yuvInfo,
+        c.forceKeepVertical != null && (this.forceKeepVertical = c.forceKeepVertical),
+        this.initCamera(c.cameraParam)
     }
-
     get MainCamera() {
         return this.mainCamera
     }
     get CgCamera() {
         return this.cgCamera
     }
+    get cameraPose() {
+        return this._cameraPose
+    }
+    set cameraFixRate(o) {
+        o == null || o < 0 ? this._cameraFixRate = 1 : this._cameraFixRate = o
+    }
     getCameraHorizonFov() {
         return this.mainCamera.fovMode == BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED ? this.mainCamera.fov : Math.PI * this.yuvInfo.fov / 180
     }
-    changeMainCameraRotationDamping(e=2e3) {
-        this.mainCamera.angularSensibility = e
+    changeMainCameraRotationDamping(o=2e3) {
+        this.mainCamera.angularSensibility = o
     }
     removeMainCameraRotationLimit() {
         this.maincameraRotLimitObserver != null && this.mainCamera.onAfterCheckInputsObservable.remove(this.maincameraRotLimitObserver)
     }
-    setMainCameraInfo(e) {
-        const {maxZ: t=1e4, minZ: r=.1, angularSensibility: n=2e3} = e;
-        this.mainCamera.maxZ = t,
-        this.mainCamera.minZ = r,
-        this.mainCamera.angularSensibility = n
+    setMainCameraInfo(o) {
+        const {maxZ: s=1e4, minZ: c=.1, angularSensibility: _=2e3} = o;
+        this.mainCamera.maxZ = s,
+        this.mainCamera.minZ = c,
+        this.mainCamera.angularSensibility = _
     }
     getMainCameraInfo() {
         return {
@@ -161,82 +165,90 @@ export default class XCameraComponent {
             angularSensibility: this.mainCamera.angularSensibility
         }
     }
-    _limitAngle(e, t) {
-        return Math.abs(Math.abs(t[0] - t[1]) - 360) < 1e-6 || (e = (e % 360 + 360) % 360,
-        t[0] = (t[0] % 360 + 360) % 360,
-        t[1] = (t[1] % 360 + 360) % 360,
-        t[0] > t[1] ? e > t[1] && e < t[0] && (Math.abs(e - t[0]) < Math.abs(e - t[1]) ? e = t[0] : e = t[1]) : e < t[0] ? e = t[0] : e > t[1] && (e = t[1])),
-        e
+    _limitAngle(o, s) {
+        if (Math.abs(Math.abs(s[0] - s[1]) - 360) < 1e-6)
+            return o;
+        if (o = (o % 360 + 360) % 360,
+        s[0] = (s[0] % 360 + 360) % 360,
+        s[1] = (s[1] % 360 + 360) % 360,
+        s[0] > s[1])
+            o > s[1] && o < s[0] && (Math.abs(o - s[0]) < Math.abs(o - s[1]) ? o = s[0] : o = s[1]);
+        else if (o < s[0] || o > s[1]) {
+            const c = (s[0] - o + 360) % 360
+              , _ = (o - s[1] + 360) % 360;
+            c < _ ? o = s[0] : o = s[1]
+        }
+        return o
     }
-    setMainCameraRotationLimit(e, t) {
+    setMainCameraRotationLimit(o, s) {
         this.maincameraRotLimitObserver != null && this.removeMainCameraRotationLimit();
-        const r = this.mainCamera
-          , {yaw: n, pitch: o, roll: a} = e
-          , {yaw: s, pitch: l, roll: u} = t;
-        if (s < 0 || l < 0 || u < 0)
-        //相机旋转限制只能设置为大于0
+        const c = this.mainCamera
+          , {yaw: _, pitch: b, roll: k} = o
+          , {yaw: j, pitch: $, roll: _e} = s;
+        if (j < 0 || $ < 0 || _e < 0)
             throw new Error("\u76F8\u673A\u65CB\u8F6C\u9650\u5236\u53EA\u80FD\u8BBE\u7F6E\u4E3A\u5927\u4E8E0");
-        const c = [o - l, o + l]
-          , h = [n - s, n + s]
-          , f = [a - u, a + u];
-        this.maincameraRotLimitObserver = r.onAfterCheckInputsObservable.add(()=>{
-            let {pitch: d, yaw: _, roll: g} = xverseRotation2Ue4(r.rotation);
-            d = this._limitAngle(d, c),
-            _ = this._limitAngle(_, h),
-            g = this._limitAngle(g, f),
-            r.rotation = ue4Rotation2Xverse({
-                pitch: d,
-                yaw: _,
-                roll: g
+        const et = [b - $, b + $]
+          , tt = [_ - j, _ + j]
+          , rt = [k - _e, k + _e];
+        this.maincameraRotLimitObserver = c.onAfterCheckInputsObservable.add(()=>{
+            let {pitch: it, yaw: nt, roll: at} = xverseRotation2Ue4(c.rotation);
+            it = this._limitAngle(it, et),
+            nt = this._limitAngle(nt, tt),
+            at = this._limitAngle(at, rt),
+            it <= 180 && it >= 0 ? it = it % 90 : it = (it - 360) % 90,
+            c.rotation = ue4Rotation2Xverse({
+                pitch: it,
+                yaw: nt,
+                roll: at
             })
         }
         )
     }
-    setMainCameraRotationLimitByAnchor(e, t, r) {
+    setMainCameraRotationLimitByAnchor(o, s, c) {
         this.maincameraRotLimitObserver != null && this.removeMainCameraRotationLimit();
-        const n = this.mainCamera
-          , o = ue4Rotation2Xverse_mesh(t)
-          , a = ue4Rotation2Xverse_mesh(r);
-        a != null && o != null && e.mesh != null && (this.maincameraRotLimitObserver = n.onAfterCheckInputsObservable.add(()=>{
-            const s = e.mesh.rotation;
-            r.yaw > 0 && (n.rotation.y <= s.y - a.y + o.y ? n.rotation.y = s.y - a.y + o.y : n.rotation.y >= s.y + a.y + o.y && (n.rotation.y = s.y + a.y + o.y)),
-            r.pitch > 0 && (n.rotation.x <= s.x - a.x + o.x ? n.rotation.x = s.x - a.x + o.x : n.rotation.x >= s.x + a.x + o.x && (n.rotation.x = s.x + a.x + o.x)),
-            r.roll > 0 && (n.rotation.z <= s.z - a.z + o.z ? n.rotation.z = s.z - a.z + o.z : n.rotation.z >= s.z + a.z + o.z && (n.rotation.z = s.z + a.z + o.z))
+        const _ = this.mainCamera
+          , b = ue4Rotation2Xverse_mesh(s)
+          , k = ue4Rotation2Xverse_mesh(c);
+        k != null && b != null && o.mesh != null && (this.maincameraRotLimitObserver = _.onAfterCheckInputsObservable.add(()=>{
+            const j = o.mesh.rotation;
+            c.yaw > 0 && (_.rotation.y <= j.y - k.y + b.y ? _.rotation.y = j.y - k.y + b.y : _.rotation.y >= j.y + k.y + b.y && (_.rotation.y = j.y + k.y + b.y)),
+            c.pitch > 0 && (_.rotation.x <= j.x - k.x + b.x ? _.rotation.x = j.x - k.x + b.x : _.rotation.x >= j.x + k.x + b.x && (_.rotation.x = j.x + k.x + b.x)),
+            c.roll > 0 && (_.rotation.z <= j.z - k.z + b.z ? _.rotation.z = j.z - k.z + b.z : _.rotation.z >= j.z + k.z + b.z && (_.rotation.z = j.z + k.z + b.z))
         }
         ))
     }
     getCameraPose() {
-        const e = xversePosition2Ue4({
+        const o = xversePosition2Ue4({
             x: this.mainCamera.position.x,
             y: this.mainCamera.position.y,
             z: this.mainCamera.position.z
         })
-          , t = xverseRotation2Ue4({
+          , s = xverseRotation2Ue4({
             x: this.mainCamera.rotation.x,
             y: this.mainCamera.rotation.y,
             z: this.mainCamera.rotation.z
         });
         return {
-            position: e,
-            rotation: t
+            position: o,
+            rotation: s
         }
     }
-    changeCameraFov(e, t) {
-        this.mainCamera.fov = e,
-        t != null && (this.mainCamera.fovMode = t == 0 ? BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED : BABYLON.Camera.FOVMODE_VERTICAL_FIXED)
+    changeCameraFov(o, s) {
+        this.mainCamera.fov = o,
+        s != null && (this.mainCamera.fovMode = s == 0 ? BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED : BABYLON.Camera.FOVMODE_VERTICAL_FIXED)
     }
-    controlCameraRotation(e, t, r=.5, n=.5) {
-        const o = {
-            pitch: n * t * 180,
-            yaw: r * e * 180,
+    controlCameraRotation(o, s, c=.5, _=.5) {
+        const b = {
+            pitch: _ * s * 180,
+            yaw: c * o * 180,
             roll: 0
         };
-        this.addRot(o)
+        this.addRot(b)
     }
-    addRot(e) {
-        const t = this.mainCamera
-          , r = ue4Rotation2Xverse_mesh(e);
-        r != null && t.rotation.addInPlace(r)
+    addRot(o) {
+        const s = this.mainCamera
+          , c = ue4Rotation2Xverse_mesh(o);
+        c != null && s.rotation.addInPlace(c)
     }
     getCameraFov() {
         return this.mainCamera.fov
@@ -247,21 +259,29 @@ export default class XCameraComponent {
     detachMainCameraController() {
         this.mainCamera.detachControl(this.canvas)
     }
-    forceChangeSavedCameraPose(e) {
-        this.saveCameraPose != null && (e.position != null && (this.saveCameraPose.position = ue4Position2Xverse(e.position)),
-        e.rotation != null && (this.saveCameraPose.rotation = ue4Rotation2Xverse(e.rotation)))
+    forceChangeSavedCameraPose(o) {
+        this.saveCameraPose != null && (o.position != null && (this.saveCameraPose.position = ue4Position2Xverse(o.position)),
+        o.rotation != null && (this.saveCameraPose.rotation = ue4Rotation2Xverse(o.rotation)))
+    }
+    InitCameraRotation() {
+        this.mainCamera.rotation.x = 0,
+        this.mainCamera.rotation.y = 0,
+        this.mainCamera.rotation.z = 0,
+        this.mainCamera.computeWorldMatrix()
     }
-    changeToFirstPersonView(e) {
+    changeToFirstPersonView(o) {
         this.saveCameraPose = {
             position: this.mainCamera.position.clone(),
             rotation: this.mainCamera.rotation.clone()
         },
+        this.InitCameraRotation(),
         this.mainCamera.attachControl(this.canvas, !0),
-        e.position != null && (this.mainCamera.position = ue4Position2Xverse(e.position)),
-        e.rotation != null && (this.mainCamera.rotation = ue4Rotation2Xverse(e.rotation))
+        o.position != null && (this.mainCamera.position = ue4Position2Xverse(o.position)),
+        o.rotation != null && (this.mainCamera.rotation = ue4Rotation2Xverse(o.rotation))
     }
     changeToThirdPersonView() {
-        this.saveCameraPose != null && this.mainCamera != null && (this.mainCamera.position = this.saveCameraPose.position.clone(),
+        this.saveCameraPose != null && this.mainCamera != null && (this.InitCameraRotation(),
+        this.mainCamera.position = this.saveCameraPose.position.clone(),
         this.mainCamera.rotation = this.saveCameraPose.rotation.clone(),
         this.mainCamera.detachControl(this.canvas))
     }
@@ -271,7 +291,44 @@ export default class XCameraComponent {
     switchToCgCamera() {
         this.switchCamera(this.cgCamera)
     }
-    moveMainCamera(e, t, r, n, o) {
-        this._moveCam(this.mainCamera, this.mainCamera.position, e, this.mainCamera.rotation, t, r, n, o)
+    moveMainCamera(o, s, c, _, b) {
+        this._moveCam(this.mainCamera, this.mainCamera.position, o, this.mainCamera.rotation, s, c, _, b)
+    }
+    inverseRotationMatrix(o) {
+        const s = new XMatrix(new XPlane(+Math.cos(o.yaw * Math.PI / 180),-Math.sin(o.yaw * Math.PI / 180),0,0),new XPlane(+Math.sin(o.yaw * Math.PI / 180),+Math.cos(o.yaw * Math.PI / 180),0,0),new XPlane(0,0,1,0),new XPlane(0,0,0,1))
+          , c = new XMatrix(new XPlane(+Math.cos(o.pitch * Math.PI / 180),0,-Math.sin(o.pitch * Math.PI / 180),0),new XPlane(0,1,0,0),new XPlane(+Math.sin(o.pitch * Math.PI / 180),0,+Math.cos(o.pitch * Math.PI / 180),0),new XPlane(0,0,0,1))
+          , _ = new XMatrix(new XPlane(1,0,0,0),new XPlane(0,+Math.cos(o.roll * Math.PI / 180),+Math.sin(o.roll * Math.PI / 180),0),new XPlane(0,-Math.sin(o.roll * Math.PI / 180),+Math.cos(o.roll * Math.PI / 180),0),new XPlane(0,0,0,1));
+        return MatrixMul(MatrixMul(s, c), _)
+    }
+    reversedZPerspectiveMatrix(o, s, c, _) {
+        return new XMatrix(new XPlane(1 / Math.tan(o),0,0,0),new XPlane(0,s / Math.tan(o) / c,0,0),new XPlane(0,0,0,1),new XPlane(0,0,_,0))
+    }
+    isInMainCamera(o, s=-.5, c=.5, _=-.5, b=.5) {
+        if (this._cameraFixRate < 1e-5)
+            return !0;
+        const k = this.getCameraPose()
+          , j = new BABYLON.Vector3(o.x - k.position.x,o.y - k.position.y,o.z - k.position.z)
+          , $ = new XMatrix(new XPlane(0,0,1,0),new XPlane(1,0,0,0),new XPlane(0,1,0,0),new XPlane(0,0,0,1))
+          , _e = MatrixMul(this.inverseRotationMatrix(k.rotation), $)
+          , et = new BABYLON.Vector3(j.x * _e.M[0][0] + j.y * _e.M[1][0] + j.z * _e.M[2][0] + _e.M[3][0],j.x * _e.M[0][1] + j.y * _e.M[1][1] + j.z * _e.M[2][1] + _e.M[3][1],j.x * _e.M[0][2] + j.y * _e.M[1][2] + j.z * _e.M[2][2] + _e.M[3][2])
+          , tt = this.reversedZPerspectiveMatrix(this.yuvInfo.fov / 2, this.yuvInfo.width, this.yuvInfo.height, 10)
+          , rt = new BABYLON.Vector3(et.x * tt.M[0][0],et.y * tt.M[1][1],et.z * tt.M[2][3])
+          , it = rt.x / rt.z * this._cameraFixRate
+          , nt = rt.y / rt.z * this._cameraFixRate;
+        return !(it < s || it > c || nt < _ || nt > b)
+    }
+    getMainCameraUV(o) {
+        if (this._cameraFixRate < 1e-5)
+            return 0;
+        const s = this.getCameraPose()
+          , c = new BABYLON.Vector3(o.x - s.position.x,o.y - s.position.y,o.z - s.position.z)
+          , _ = new XMatrix(new XPlane(0,0,1,0),new XPlane(1,0,0,0),new XPlane(0,1,0,0),new XPlane(0,0,0,1))
+          , b = MatrixMul(this.inverseRotationMatrix(s.rotation), _)
+          , k = new BABYLON.Vector3(c.x * b.M[0][0] + c.y * b.M[1][0] + c.z * b.M[2][0] + b.M[3][0],c.x * b.M[0][1] + c.y * b.M[1][1] + c.z * b.M[2][1] + b.M[3][1],c.x * b.M[0][2] + c.y * b.M[1][2] + c.z * b.M[2][2] + b.M[3][2])
+          , j = this.reversedZPerspectiveMatrix(this.yuvInfo.fov / 2, this.yuvInfo.width, this.yuvInfo.height, 10)
+          , $ = new BABYLON.Vector3(k.x * j.M[0][0],k.y * j.M[1][1],k.z * j.M[2][3])
+          , _e = $.x / $.z * 2 * this._cameraFixRate
+          , et = $.y / $.z * 2 * this._cameraFixRate;
+        return Math.sqrt(_e * _e + et * et)
     }
 }

+ 61 - 64
src/XDecal.js

@@ -1,51 +1,48 @@
 import EMeshType from "./enum/EMeshType.js"
 import XDecalTextureError from "./error/XDecalTextureError.js"
+import XDecalError from "./error/XDecalError.js"
 import Logger from "./Logger.js"
 
 const logger = new Logger('DecalManager')
 
 export default class XDecal {
-    constructor(e) {
-        E(this, "_id");
-        E(this, "meshPath");
-        E(this, "_low_model", []);
-        E(this, "_mat", null);
-        E(this, "scene");
-        E(this, "_skinInfo");
-        E(this, "sourceMatId", "");
-        E(this, "loadModel", async()=>new Promise((e,t)=>{
-            typeof this.meshPath == "string" ? BABYLON.SceneLoader.LoadAssetContainerAsync("", this.meshPath, this.scene, null, ".glb").then(r=>{
-                for (let n = r.materials.length - 1; n >= 0; --n)
-                    r.materials[n].dispose();
-                for (let n = 0; n < r.meshes.length; ++n)
-                    r.meshes[n].visibility = 1,
-                    r.meshes[n].isPickable = !0,
-                    r.meshes[n].checkCollisions = !1,
-                    "hasVertexAlpha"in r.meshes[n] && (r.meshes[n].hasVertexAlpha = !1),
-                    this.scene.addMesh(r.meshes[n]),
+    constructor(o) {
+        this._low_model = [],
+        this._mat = null,
+        this.sourceMatId = "",
+        this.loadModel = async()=>new Promise((k,j)=>{
+            typeof this.meshPath == "string" ? BABYLON.SceneLoader.LoadAssetContainerAsync("", this.meshPath, this.scene, null, ".glb").then($=>{
+                for (let _e = $.materials.length - 1; _e >= 0; --_e)
+                    $.materials[_e].dispose();
+                for (let _e = 0; _e < $.meshes.length; ++_e)
+                    $.meshes[_e].visibility = 1,
+                    $.meshes[_e].isPickable = !0,
+                    $.meshes[_e].checkCollisions = !1,
+                    "hasVertexAlpha"in $.meshes[_e] && ($.meshes[_e].hasVertexAlpha = !1),
+                    this.scene.addMesh($.meshes[_e]),
                     this._low_model.push(new XStaticMesh({
                         id: this._id,
-                        mesh: r.meshes[n],
+                        mesh: $.meshes[_e],
                         xtype: EMeshType.Decal,
                         skinInfo: this._skinInfo
                     })),
                     this.toggle(!1);
-                e(!0)
+                k(!0)
             }
-            ).catch(r=>{
-                t(new XDecalError(`[Engine] decal load model error! ${r}`))
+            ).catch($=>{
+                j(new XDecalError(`[Engine] decal load model error! ${$}`))
             }
-            ) : t(new XDecalError("[Engine] decal inport mesh is not string!"))
+            ) : j(new XDecalError("[Engine] decal inport mesh is not string!"))
         }
-        ).catch(e=>{
-            new XDecalError(`[Engine] decal loadModel ${e}`)
+        ).catch(k=>{
+            new XDecalError(`[Engine] decal loadModel ${k}`)
         }
-        ));
-        const {id: t, scene: r, meshPath: n, skinInfo: o="default"} = e;
-        this._id = t,
-        this.scene = r,
-        this.meshPath = n,
-        this._skinInfo = o
+        );
+        const {id: s, scene: c, meshPath: _, skinInfo: b="default"} = o;
+        this._id = s,
+        this.scene = c,
+        this.meshPath = _,
+        this._skinInfo = b
     }
     get skinInfo() {
         return this._skinInfo
@@ -59,50 +56,50 @@ export default class XDecal {
     get id() {
         return this._id
     }
-    toggle(e) {
-        for (let t = 0; t < this._low_model.length; ++t)
-            e == !0 ? this._low_model[t].show() : this._low_model[t].hide()
+    toggle(o) {
+        for (let s = 0; s < this._low_model.length; ++s)
+            o == !0 ? this._low_model[s].show() : this._low_model[s].hide()
     }
-    setMat(e) {
-        this._mat = e;
-        for (let t = 0; t < this._low_model.length; ++t)
-            this._low_model[t].mesh.material = this._mat;
-        this.toggle(!0)
+    setMat(o) {
+        this._mat = o;
+        for (let s = 0; s < this._low_model.length; ++s)
+            this._low_model[s].mesh.material = this._mat;
+        GEngine.engineOption.bDisableLocalRender ? this.toggle(!1) : this.toggle(!0)
     }
-    changeModel(e="") {
-        return e != "" && (this.meshPath = e),
+    changeModel(o="") {
+        return o != "" && (this.meshPath = o),
         this.meshPath == "" ? (logger.error("[Engine] changeModel Error! meshPath is empty"),
-        Promise.reject(new XDecalTextureError("[Engine] changeModel Error! meshPath is empty"))) : new Promise((t,r)=>BABYLON.SceneLoader.LoadAssetContainerAsync("", this.meshPath, this.scene, null, ".glb").then(n=>{
-            for (let a = n.materials.length - 1; a >= 0; --a)
-                n.materials[a].dispose();
-            const o = [];
-            for (let a = 0; a < n.meshes.length; ++a)
-                n.meshes[a].visibility = 0,
-                n.meshes[a].isPickable = !0,
-                n.meshes[a].checkCollisions = !1,
-                "hasVertexAlpha"in n.meshes[a] && (n.meshes[a].hasVertexAlpha = !1),
-                this._mat != null && (n.meshes[a].material = this._mat),
-                this.scene.addMesh(n.meshes[a]),
-                o.push(new XStaticMesh({
+        Promise.reject(new XDecalTextureError("[Engine] changeModel Error! meshPath is empty"))) : new Promise((s,c)=>BABYLON.SceneLoader.LoadAssetContainerAsync("", this.meshPath, this.scene, null, ".glb").then(_=>{
+            for (let k = _.materials.length - 1; k >= 0; --k)
+                _.materials[k].dispose();
+            const b = [];
+            for (let k = 0; k < _.meshes.length; ++k)
+                _.meshes[k].visibility = 0,
+                _.meshes[k].isPickable = !0,
+                _.meshes[k].checkCollisions = !1,
+                "hasVertexAlpha"in _.meshes[k] && (_.meshes[k].hasVertexAlpha = !1),
+                this._mat != null && (_.meshes[k].material = this._mat),
+                this.scene.addMesh(_.meshes[k]),
+                b.push(new XStaticMesh({
                     id: this._id,
-                    mesh: n.meshes[a],
+                    mesh: _.meshes[k],
                     xtype: EMeshType.Decal,
                     skinInfo: this._skinInfo
                 }));
-            e != "" && this.cleanMesh(),
-            this._low_model = o,
-            this._mat != null && this.toggle(!0),
-            t(this)
+            o != "" && this.cleanMesh(),
+            this._low_model = b,
+            this._mat != null && (GEngine.engineOption.bDisableLocalRender ? this.toggle(!1) : this.toggle(!0)),
+            s(this)
         }
-        ).catch(n=>{
-            logger.error("[Engine] Create decal error! " + n),
-            r(new XDecalError("[Engine] Create decal error! " + n))
+        ).catch(_=>{
+            logger.error("[Engine] Create decal error! " + _),
+            c(new XDecalError("[Engine] Create decal error! " + _))
         }
         ))
     }
-    cleanMesh(e=!1, t=!1) {
+    cleanMesh(o=!1, s=!1) {
         logger.info("[Engine] Decal Model clean mesh");
-        for (let r = 0; r < this._low_model.length; ++r)
-            this._low_model[r].dispose(e, t)
+        for (let c = 0; c < this._low_model.length; ++c)
+            this._low_model[c].dispose(o, s)
     }
 }

+ 179 - 179
src/XDecalManager.js

@@ -1,230 +1,230 @@
+import Logger from "./Logger.js"
+import XDecal from "./XDecal.js"
+import XDecalError from "./error/XDecalError.js"
+
+const logger = new Logger("XDecalManager");
 export default class XDecalManager {
-    constructor(e) {
-        E(this, "scene");
-        E(this, "_decal");
-        E(this, "_mat");
-        E(this, "_sharedMat");
-        E(this, "_scenemanager");
-        this._decal = new Map,
-        this._mat = new Map,
-        this._sharedMat = new Map,
-        this._scenemanager = e,
-        this.scene = e.Scene
-    }
     get decals() {
         return Array.from(this._decal.values())
     }
     getMesh() {
         return this._decal
     }
-    async addDecal(e) {
-        const {id: t, meshPath: r, skinInfo: n="default"} = e;
-        return this._decal.get(t) ? (logger.warn(`[Engine] Cannot add decal with an existing id: [${t}], meshPath: ${r}, skinInfo:${n}`),
-        Promise.resolve(!0)) : (logger.info(`[Engine] addDecal wiht id:[${t}], meshPath: ${r}, skinInfo:${n}`),
-        new Promise((o,a)=>this._scenemanager.urlTransformer(r).then(s=>new Promise((l,u)=>{
-            if (this._decal.get(t))
-                l(!0);
+    constructor(o) {
+        this._decal = new Map,
+        this._mat = new Map,
+        this._sharedMat = new Map,
+        this._scenemanager = o,
+        this.scene = o.Scene
+    }
+    async addDecal(o) {
+        const {id: s, meshPath: c, skinInfo: _="default"} = o;
+        return this._decal.get(s) ? (logger.warn(`[Engine] Cannot add decal with an existing id: [${s}], meshPath: ${c}, skinInfo:${_}`),
+        Promise.resolve(!0)) : (logger.info(`[Engine] addDecal wiht id:[${s}], meshPath: ${c}, skinInfo:${_}`),
+        new Promise((b,k)=>this._scenemanager.urlTransformer(c).then(j=>new Promise(($,_e)=>{
+            if (this._decal.get(s))
+                $(!0);
             else {
-                const c = new XDecal({
-                    id: t,
+                const et = new XDecal({
+                    id: s,
                     scene: this.scene,
-                    meshPath: s,
-                    skinInfo: n
+                    meshPath: j,
+                    skinInfo: _
                 });
-                this._decal.set(t, c),
-                c.loadModel().then(()=>{
-                    l(!0)
+                this._decal.set(s, et),
+                et.loadModel().then(()=>{
+                    $(!0)
                 }
-                ).catch(h=>{
-                    logger.error(`[Engine] addDecal Error! id: [${t}], meshpath:${r}, skin: ${n}. ${h}`),
-                    u(new XDecalError(`[Engine] addDecal Error! id: [${t}], meshpath:${r}, skin: ${n}. ${h}`))
+                ).catch(tt=>{
+                    logger.error(`[Engine] addDecal Error! id: [${s}], meshpath:${c}, skin: ${_}. ${tt}`),
+                    _e(new XDecalError(`[Engine] addDecal Error! id: [${s}], meshpath:${c}, skin: ${_}. ${tt}`))
                 }
                 )
             }
         }
-        )).then(s=>{
-            s == !0 ? o(!0) : a(!1)
+        )).then(j=>{
+            j == !0 ? b(!0) : k(!1)
         }
-        ).catch(s=>{
-            logger.error(`[Engine] Add Decal error! id: [${t}], meshpath:${r}, skin:${n}. ${s}`),
-            a(new XDecalError(`[Engine] addDecal  error! id: [${t}], meshpath:${r}, skin:${n}. ${s}`))
+        ).catch(j=>{
+            logger.error(`[Engine] Add Decal error! id: [${s}], meshpath:${c}, skin:${_}. ${j}`),
+            k(new XDecalError(`[Engine] addDecal  error! id: [${s}], meshpath:${c}, skin:${_}. ${j}`))
         }
         )))
     }
-    setDecalTexture(e) {
-        const {id: t, buffer: r, isDynamic: n=!1, width: o=1100, height: a=25, slots: s=1, visibleSlots: l=1} = e
-          , u = !0;
-        return logger.info(`[Engine] setDecalTexture wiht id:[${t}]`),
-        new Promise((c,h)=>{
-            const f = this._decal.get(t);
-            if (f != null)
-                if (this._mat.get(t) != null)
+    setDecalTexture(o) {
+        const {id: s, buffer: c, isDynamic: _=!1, width: b=1100, height: k=25, slots: j=1, visibleSlots: $=1} = o
+          , _e = !0;
+        return logger.info(`[Engine] setDecalTexture wiht id:[${s}]`),
+        new Promise((et,tt)=>{
+            const rt = this._decal.get(s);
+            if (rt != null)
+                if (this._mat.get(s) != null)
                     this.changeDecalTexture({
-                        id: t,
-                        buffer: r,
-                        isUrl: u,
-                        isDynamic: n,
-                        width: o,
-                        height: a,
-                        slots: s,
-                        visibleSlots: l
+                        id: s,
+                        buffer: c,
+                        isUrl: _e,
+                        isDynamic: _,
+                        width: b,
+                        height: k,
+                        slots: j,
+                        visibleSlots: $
                     }),
-                    c(!0);
+                    et(!0);
                 else {
-                    const d = new XDecalMaterial(t,this.scene);
-                    d.setTexture(r, u, n, o, a, s, l).then(()=>{
-                        f.setMat(d.getMat()),
-                        this._decal.set(t, f),
-                        this._mat.set(t, d),
-                        c(!0)
+                    const it = new XDecalMaterial(s,this.scene);
+                    it.setTexture(c, _e, _, b, k, j, $).then(()=>{
+                        rt.setMat(it.getMat()),
+                        this._decal.set(s, rt),
+                        this._mat.set(s, it),
+                        et(!0)
                     }
-                    ).catch(_=>{
-                        logger.error("[Engine] setDecalTexture Error! " + _),
-                        h(new XDecalTextureError(`[Engine] decal set texture error! ${_}`))
+                    ).catch(nt=>{
+                        logger.error("[Engine] setDecalTexture Error! " + nt),
+                        tt(new XDecalTextureError(`[Engine] decal set texture error! ${nt}`))
                     }
                     )
                 }
             else
-                logger.error("[Engine] Error! decal id: [" + t + "] is not find!"),
-                h(new XDecalTextureError(`[Engine] decal id: [${t}] is not find!`))
+                logger.error("[Engine] Error! decal id: [" + s + "] is not find!"),
+                tt(new XDecalTextureError(`[Engine] decal id: [${s}] is not find!`))
         }
         )
     }
-    async shareDecal(e) {
-        const {idTar: t, meshPath: r, idSrc: n, skinInfo: o="default"} = e;
-        return this._decal.has(n) && !this._decal.has(t) && this._mat.has(n) && !this._mat.has(t) ? (logger.info(`[Engine] shareDecal wiht idTar:[${t}], idSrc:[${n}], skinInfo: ${o}, meshPath: ${r}`),
-        new Promise((a,s)=>this._scenemanager.urlTransformer(r).then(l=>{
-            const u = new XDecal({
-                id: t,
+    async shareDecal(o) {
+        const {idTar: s, meshPath: c, idSrc: _, skinInfo: b="default"} = o;
+        return this._decal.has(_) && !this._decal.has(s) && this._mat.has(_) && !this._mat.has(s) ? (logger.info(`[Engine] shareDecal wiht idTar:[${s}], idSrc:[${_}], skinInfo: ${b}, meshPath: ${c}`),
+        new Promise((k,j)=>this._scenemanager.urlTransformer(c).then($=>{
+            const _e = new XDecal({
+                id: s,
                 scene: this.scene,
-                meshPath: l,
-                skinInfo: o
+                meshPath: $,
+                skinInfo: b
             })
-              , c = this._mat.get(n);
-            c != null && (u.setMat(c.getMat()),
-            u.sourceMatId = n,
-            this._decal.set(t, u),
-            this.addSharedMatCount(n)),
-            a(!0)
+              , et = this._mat.get(_);
+            et != null && (_e.setMat(et.getMat()),
+            _e.sourceMatId = _,
+            this._decal.set(s, _e),
+            this.addSharedMatCount(_)),
+            k(!0)
         }
-        ).catch(l=>{
-            s(new XDecalError(`[Engine] decal shareDecal error! ${l}`))
+        ).catch($=>{
+            j(new XDecalError(`[Engine] decal shareDecal error! ${$}`))
         }
-        ))) : (logger.error(`[Engine] shareDecal Error. idSrc: [${n}] not exist! or idTar: [${t}] exists!`),
-        Promise.reject(`[Engine] shareDecal Error. idSrc: [${n}] not exist! or idTar: [${t}] exists!`))
-    }
-    async changeDecalModel(e) {
-        const {id: t, meshPath: r} = e
-          , n = this._decal.get(t);
-        return new Promise((o,a)=>n != null ? (logger.info(`[Engine] changeDecalModel id:${t}`),
-        n.changeModel(r).then(()=>{
-            this._decal.set(t, n),
-            o(!0)
+        ))) : (logger.error(`[Engine] shareDecal Error. idSrc: [${_}] not exist! or idTar: [${s}] exists!`),
+        Promise.reject(`[Engine] shareDecal Error. idSrc: [${_}] not exist! or idTar: [${s}] exists!`))
+    }
+    changeDecalModel(o) {
+        const {id: s, meshPath: c} = o
+          , _ = this._decal.get(s);
+        return new Promise((b,k)=>_ != null ? (logger.info(`[Engine] changeDecalModel id:${s}`),
+        _.changeModel(c).then(()=>{
+            this._decal.set(s, _),
+            b(!0)
         }
-        )) : (logger.warn(`[Engine] changeDecalModel id:${t} is not exist`),
-        a(`[Engine] changeDecalModel id:${t} is not exist`)))
-    }
-    changeDecalTexture(e) {
-        const {id: t, buffer: r, isUrl: n=!1, isDynamic: o=!1, width: a=1110, height: s=25, slots: l=1, visibleSlots: u=1} = e
-          , c = this._mat.get(t);
-        c != null && this._decal.has(t) ? (c.changeTexture(r, n, o, a, s, l, u),
-        this._mat.set(t, c)) : logger.error(`[Engine] changeDecalTexture Error. id:${t} is not exist`)
-    }
-    deleteDecal(e) {
-        var t, r;
-        if (this._decal.has(e)) {
-            const n = this._decal.get(e);
-            n != null && n.cleanMesh(),
-            this._sharedMat.get(e) != null ? this.minusSharedMatCount(e) : this._mat.get(e) != null ? ((t = this._mat.get(e)) == null || t.cleanTexture(),
-            this._mat.delete(e)) : ((r = n.sourceMatId) == null ? void 0 : r.length) > 0 && this.minusSharedMatCount(n.sourceMatId),
-            this._decal.delete(e)
+        )) : (logger.warn(`[Engine] changeDecalModel id:${s} is not exist`),
+        k(`[Engine] changeDecalModel id:${s} is not exist`)))
+    }
+    changeDecalTexture(o) {
+        const {id: s, buffer: c, isUrl: _=!1, isDynamic: b=!1, width: k=1110, height: j=25, slots: $=1, visibleSlots: _e=1} = o
+          , et = this._mat.get(s);
+        et != null && this._decal.has(s) ? (et.changeTexture(c, _, b, k, j, $, _e),
+        this._mat.set(s, et)) : logger.error(`[Engine] changeDecalTexture Error. id:${s} is not exist`)
+    }
+    deleteDecal(o) {
+        var s, c;
+        if (this._decal.has(o)) {
+            const _ = this._decal.get(o);
+            _ != null && _.cleanMesh(),
+            this._sharedMat.get(o) != null ? this.minusSharedMatCount(o) : this._mat.get(o) != null ? ((s = this._mat.get(o)) == null || s.cleanTexture(),
+            this._mat.delete(o)) : ((c = _.sourceMatId) == null ? void 0 : c.length) > 0 && this.minusSharedMatCount(_.sourceMatId),
+            this._decal.delete(o)
         }
     }
-    deleteDecalBySkinInfo(e) {
-        for (const [t,r] of this._decal.entries())
-            r.skinInfo == e && this.deleteDecal(t)
-    }
-    addSharedMatCount(e) {
-        const t = this._sharedMat.get(e);
-        t != null ? this._sharedMat.set(e, t + 1) : this._sharedMat.set(e, 1)
-    }
-    minusSharedMatCount(e) {
-        var r;
-        const t = this._sharedMat.get(e);
-        t != null && (this._sharedMat.set(e, t - 1),
-        t == 0 && (this._sharedMat.delete(e),
-        (r = this._mat.get(e)) == null || r.cleanTexture(),
-        this._mat.delete(e)))
-    }
-    toggle(e, t) {
-        const r = this._decal.get(e);
-        r == null || r.toggle(t)
-    }
-    toggleDecalBySkinInfo(e, t) {
-        for (const [r,n] of this._decal.entries())
-            n.skinInfo == e && n.toggle(t)
-    }
-    updateTexAsWords(e, t, r={}) {
-        const {clearArea: n=!0, w: o=480, h: a=480, y: s=a / 2, fontsize: l=70, slots: u=1, visibleSlots: c=1, font: h="black-body", color: f="white", fontweight: d=100} = r;
-        let {x: _=o / 2} = r;
-        const g = this._mat.get(e);
-        if (g) {
-            _ == -1 && (_ = (g.getUOffset() + c / u) % 1 * o * u);
-            const v = g.getMat().diffuseTexture
-              , y = v.getContext();
-            n && y.clearRect(_ - o / 2, s - a / 2, o, a),
-            y.textAlign = "center",
-            y.textBaseline = "middle",
-            v.drawText(t, _, s, d + " " + l + "px " + h, f, "transparent", !0),
-            v.hasAlpha = !0,
-            v.update()
+    deleteDecalBySkinInfo(o) {
+        for (const [s,c] of this._decal.entries())
+            c.skinInfo == o && this.deleteDecal(s)
+    }
+    addSharedMatCount(o) {
+        const s = this._sharedMat.get(o);
+        s != null ? this._sharedMat.set(o, s + 1) : this._sharedMat.set(o, 1)
+    }
+    minusSharedMatCount(o) {
+        var c;
+        const s = this._sharedMat.get(o);
+        s != null && (this._sharedMat.set(o, s - 1),
+        s == 0 && (this._sharedMat.delete(o),
+        (c = this._mat.get(o)) == null || c.cleanTexture(),
+        this._mat.delete(o)))
+    }
+    toggle(o, s) {
+        const c = this._decal.get(o);
+        c == null || c.toggle(s)
+    }
+    toggleDecalBySkinInfo(o, s) {
+        for (const [c,_] of this._decal.entries())
+            _.skinInfo == o && _.toggle(s)
+    }
+    updateTexAsWords(o, s, c={}) {
+        const {clearArea: _=!0, w: b=480, h: k=480, y: j=k / 2, fontsize: $=70, slots: _e=1, visibleSlots: et=1, font: tt="black-body", color: rt="white", fontweight: it=100} = c;
+        let {x: nt=b / 2} = c;
+        const at = this._mat.get(o);
+        if (at) {
+            nt == -1 && (nt = (at.getUOffset() + et / _e) % 1 * b * _e);
+            const st = at.getMat().diffuseTexture
+              , lt = st.getContext();
+            _ && lt.clearRect(nt - b / 2, j - k / 2, b, k),
+            lt.textAlign = "center",
+            lt.textBaseline = "middle",
+            st.drawText(s, nt, j, it + " " + $ + "px " + tt, rt, "transparent", !0),
+            st.hasAlpha = !0,
+            st.update()
         }
     }
-    async updateTexAsImg(e, t, r={}) {
-        const {clearArea: n=!0, w: o=480, h: a=480, x: s=o / 2, y: l=a / 2, clearW: u=o, clearH: c=a} = r;
-        return t == null || t == null || t == "" ? (logger.error(`[Engine] updateTexAsImg Error. id: [${e}], newBuffer is Null or ""!`),
-        Promise.reject(new XDecalError(`[Engine] updateTexAsImg Error. id: [${e}], newBuffer is Null or ""!`))) : new Promise((h,f)=>this._scenemanager.urlTransformer(t).then(d=>new Promise((_,g)=>{
-            const m = this._mat.get(e);
-            if (m) {
-                const y = m.getMat().diffuseTexture;
-                if (typeof t == "string") {
-                    const b = new Image;
-                    b.crossOrigin = "anonymous",
-                    b.src = d,
-                    b.onload = ()=>{
-                        const T = y.getContext();
-                        n && T.clearRect(s - u / 2, l - c / 2, u, c),
-                        T.drawImage(b, s - o / 2, l - a / 2, o, a),
-                        y.update(),
-                        _(!0)
+    async updateTexAsImg(o, s, c={}) {
+        const {clearArea: _=!0, w: b=480, h: k=480, x: j=b / 2, y: $=k / 2, clearW: _e=b, clearH: et=k} = c;
+        return s == null || s == null || s == "" ? (logger.error(`[Engine] updateTexAsImg Error. id: [${o}], newBuffer is Null or ""!`),
+        Promise.reject(new XDecalError(`[Engine] updateTexAsImg Error. id: [${o}], newBuffer is Null or ""!`))) : new Promise((tt,rt)=>this._scenemanager.urlTransformer(s).then(it=>new Promise((nt,at)=>{
+            const ot = this._mat.get(o);
+            if (ot) {
+                const lt = ot.getMat().diffuseTexture;
+                if (typeof s == "string") {
+                    const ut = new Image;
+                    ut.crossOrigin = "anonymous",
+                    ut.src = it,
+                    ut.onload = ()=>{
+                        const ct = lt.getContext();
+                        _ && ct.clearRect(j - _e / 2, $ - et / 2, _e, et),
+                        ct.drawImage(ut, j - b / 2, $ - k / 2, b, k),
+                        lt.update(),
+                        nt(!0)
                     }
                     ,
-                    b.onerror = ()=>{
-                        logger.error(`[Engine] updateTexAsImg Error.newImg load error. id: [${e}], decalMat is Null or undefined!`),
-                        g(new XDecalError(`[Engine] updateTexAsImg Error. id: [${e}], decalMat is Null or undefined!`))
+                    ut.onerror = ()=>{
+                        logger.error(`[Engine] updateTexAsImg Error.newImg load error. id: [${o}], decalMat is Null or undefined!`),
+                        at(new XDecalError(`[Engine] updateTexAsImg Error. id: [${o}], decalMat is Null or undefined!`))
                     }
                 } else
-                    logger.error(`[Engine] updateTexAsImg Error. id: [${e}], Buffer is not string!`),
-                    g(new XDecalError(`[Engine] updateTexAsImg Error. id: [${e}], Buffer is not string!`))
+                    logger.error(`[Engine] updateTexAsImg Error. id: [${o}], Buffer is not string!`),
+                    at(new XDecalError(`[Engine] updateTexAsImg Error. id: [${o}], Buffer is not string!`))
             } else
-                logger.error(`[Engine] updateTexAsImg Error. id: [${e}], decalMat is Null or undefined!`),
-                g(new XDecalError(`[Engine] updateTexAsImg Error. id: [${e}], decalMat is Null or undefined!`))
+                logger.error(`[Engine] updateTexAsImg Error. id: [${o}], decalMat is Null or undefined!`),
+                at(new XDecalError(`[Engine] updateTexAsImg Error. id: [${o}], decalMat is Null or undefined!`))
         }
-        ).then(_=>{
-            _ == !0 ? h(!0) : (logger.error(`[Engine] updateTexAsImg Error. id: [${e}] !`),
-            f(new XDecalError(`[Engine] updateTexAsImg error! id: [${e}]`)))
+        ).then(nt=>{
+            nt == !0 ? tt(!0) : (logger.error(`[Engine] updateTexAsImg Error. id: [${o}] !`),
+            rt(new XDecalError(`[Engine] updateTexAsImg error! id: [${o}]`)))
         }
-        ).catch(_=>{
-            logger.error(`[Engine] updateTexAsImg Error. id: [${e}]. ${_}`)
+        ).catch(nt=>{
+            logger.error(`[Engine] updateTexAsImg Error. id: [${o}]. ${nt}`)
         }
         )))
     }
-    startAnime(e, t) {
-        logger.info(`[Engine] Decal Start Anime. [${e}]`);
-        const {speed: r=.001, callback: n} = t
-          , o = this._mat.get(e);
-        o ? (o.do_animation(r),
-        n && o.uOffsetObserverable.add(n)) : (logger.error(`[Engine] startAnime Error. id: [${e}] is not exist!`),
-        new XDecalError(`[Engine] startAnime Error. id: [${e}] is not exist!`))
+    startAnime(o, s) {
+        logger.info(`[Engine] Decal Start Anime. [${o}]`);
+        const {speed: c=.001, callback: _} = s
+          , b = this._mat.get(o);
+        b ? (b.do_animation(c),
+        _ && b.uOffsetObserverable.add(_)) : (logger.error(`[Engine] startAnime Error. id: [${o}] is not exist!`),
+        new XDecalError(`[Engine] startAnime Error. id: [${o}] is not exist!`))
     }
 }

+ 46 - 50
src/XDecalMaterial.js

@@ -1,81 +1,77 @@
 
 import XDecalTextureError from "./error/XDecalTextureError"
+import Logger from "./Logger.js"
+const logger = new Logger("XDecalMaterial");
 
 export default class XDecalMaterial {
-    constructor(e, t) {
-        E(this, "_id");
-        E(this, "_tex");
-        E(this, "scene");
-        E(this, "_mat");
-        E(this, "_speed", .001);
-        E(this, "_slots", 1);
-        E(this, "_visibleSlots", 1);
-        E(this, "_isRegisterAnimation");
-        E(this, "_animeObserver", null);
-        E(this, "_uOffsetObserverable");
-        E(this, "reg_mat_update", ()=>{
-            const e = this._mat.diffuseTexture;
-            e != null && (e.uOffset = e.uOffset + this._speed,
-            e.uOffset > 1 && (e.uOffset -= 1),
-            Math.round(e.uOffset % (1 / this._slots) / this._speed) == 0 && this._uOffsetObserverable.notifyObservers(this))
+    constructor(o, s) {
+        this._speed = .001,
+        this._slots = 1,
+        this._visibleSlots = 1,
+        this._animeObserver = null,
+        this.reg_mat_update = ()=>{
+            const c = this._mat.diffuseTexture;
+            c != null && (c.uOffset = c.uOffset + this._speed,
+            c.uOffset > 1 && (c.uOffset -= 1),
+            Math.round(c.uOffset % (1 / this._slots) / this._speed) == 0 && this._uOffsetObserverable.notifyObservers(this))
         }
-        );
-        E(this, "setTexture", async(e,t=!0,r=!1,n=1,o=1,a=1,s=1)=>new Promise((l,u)=>{
-            this._slots = a,
-            this._visibleSlots = s;
-            const c = this._tex;
-            r ? (this._tex = new BABYLON.DynamicTexture("dyTex",{
-                width: n,
-                height: o
+        ,
+        this.setTexture = async(c,_=!0,b=!1,k=1,j=1,$=1,_e=1)=>new Promise((et,tt)=>{
+            this._slots = $,
+            this._visibleSlots = _e;
+            const rt = this._tex;
+            b ? (this._tex = new BABYLON.DynamicTexture("dyTex",{
+                width: k,
+                height: j
             },this.scene,!0,BABYLON.Texture.BILINEAR_SAMPLINGMODE),
             this._tex.name = "decal_dy_" + this._id,
-            this._tex.uScale = s / a,
+            this._tex.uScale = _e / $,
             this._tex.vScale = -1,
             this._tex.vOffset = 1,
             this._tex.wrapU = 1,
-            this._mat.emissiveColor = new BABYLON.Color3(.95,.95,.95),
+            this._mat.emissiveColor = new BABYLON.Color3(.9,.9,.9),
             this._mat.diffuseTexture = this._tex,
             this._mat.diffuseTexture.hasAlpha = !0,
             this._mat.useAlphaFromDiffuseTexture = !0,
             this._mat.backFaceCulling = !1,
-            this._mat.transparencyMode = BABYLON.Material.MATERIAL_ALPHATEST,
-            c != null && c.dispose(),
-            l(!0)) : !r && t && typeof e == "string" ? this._tex = new BABYLON.Texture(e,this.scene,!0,!1,BABYLON.Texture.BILINEAR_SAMPLINGMODE,()=>{
+            this._mat.transparencyMode = Material.MATERIAL_ALPHABLEND,
+            rt != null && rt.dispose(),
+            et(!0)) : !b && _ && typeof c == "string" ? this._tex = new BABYLON.Texture(c,this.scene,!0,!1,BABYLON.Texture.BILINEAR_SAMPLINGMODE,()=>{
                 this._tex.name = "decal_" + this._id,
-                this._mat.emissiveTexture = this._tex,
+                this._mat.emissiveColor = new BABYLON.Color3(.9,.9,.9),
                 this._mat.diffuseTexture = this._tex,
                 this._mat.diffuseTexture.hasAlpha = !0,
                 this._mat.useAlphaFromDiffuseTexture = !0,
-                this._mat.transparencyMode = BABYLON.Material.MATERIAL_ALPHATEST,
-                c != null && c.dispose(),
-                l(!0)
+                this._mat.transparencyMode = Material.MATERIAL_ALPHABLEND,
+                rt != null && rt.dispose(),
+                et(!0)
             }
             ,()=>{
                 logger.error("[Engine] decal create texture error!"),
-                u(new XDecalTextureError("[Engine] decal create texture error!"))
+                tt(new XDecalTextureError("[Engine] decal create texture error!"))
             }
             ,null,!0) : this._tex = new BABYLON.Texture("data:decal_" + this._id,this.scene,!0,!1,BABYLON.Texture.BILINEAR_SAMPLINGMODE,()=>{
                 this._tex.name = "decal_" + this._id,
-                this._mat.emissiveTexture = this._tex,
+                this._mat.emissiveColor = new BABYLON.Color3(.9,.9,.9),
                 this._mat.diffuseTexture = this._tex,
                 this._mat.diffuseTexture.hasAlpha = !0,
                 this._mat.useAlphaFromDiffuseTexture = !0,
-                this._mat.transparencyMode = Material.MATERIAL_ALPHATEST,
-                c != null && c.dispose(),
-                l(!0)
+                this._mat.transparencyMode = Material.MATERIAL_ALPHABLEND,
+                rt != null && rt.dispose(),
+                et(!0)
             }
             ,()=>{
                 logger.error("[Engine] decal create texture error!"),
-                u(new XDecalTextureError("[Engine] decal create texture error!"))
+                tt(new XDecalTextureError("[Engine] decal create texture error!"))
             }
-            ,e,!0)
+            ,c,!0)
         }
-        ));
-        this._id = e,
-        this.scene = t,
+        ),
+        this._id = o,
+        this.scene = s,
         this._mat = new BABYLON.StandardMaterial("decalMat_" + this._id,this.scene),
         this._isRegisterAnimation = !1,
-        this._uOffsetObserverable = new Observable
+        this._uOffsetObserverable = new BABYLON.Observable
     }
     get uOffsetObserverable() {
         return this._uOffsetObserverable
@@ -83,23 +79,23 @@ export default class XDecalMaterial {
     getMat() {
         return this._mat
     }
-    set speed(e) {
-        this._speed = e
+    set speed(o) {
+        this._speed = o
     }
     getUOffset() {
         return this._tex.uOffset
     }
-    do_animation(e) {
-        this._speed = e,
+    do_animation(o) {
+        this._speed = o,
         this._isRegisterAnimation == !1 && (this._isRegisterAnimation = !0,
         this._animeObserver = this.scene.onBeforeRenderObservable.add(()=>{
             this.reg_mat_update()
         }
         ))
     }
-    changeTexture(e, t=!1, r=!1, n=1, o=1, a=1, s=1) {
+    changeTexture(o, s=!1, c=!1, _=1, b=1, k=1, j=1) {
         return this._mat == null || this._tex == null ? (logger.error("[Engine] Decal Mat is null or tex is null"),
-        Promise.reject(new XDecalTextureError("[Engine] Decal Mat is null or tex is null"))) : this.setTexture(e, t, r, n, o, a, s)
+        Promise.reject(new XDecalTextureError("[Engine] Decal Mat is null or tex is null"))) : this.setTexture(o, s, c, _, b, k, j)
     }
     cleanTexture() {
         logger.info("[Engine] Decal clean Texture"),

+ 6 - 3
src/XEngineRunTimeStats.js

@@ -2,8 +2,11 @@ import RunTimeArray from "./RunTimeArray.js"
 
 export default class XEngineRunTimeStats {
     constructor() {
-        E(this, "timeArray_loadStaticMesh", new RunTimeArray);
-        E(this, "timeArray_updateStaticMesh", new RunTimeArray);
-        E(this, "timeArray_addAvatarToScene", new RunTimeArray)
+        this.timeArray_loadStaticMesh = new RunTimeArray,
+        this.timeArray_updateStaticMesh = new RunTimeArray,
+        this.timeArray_addAvatarToScene = new RunTimeArray,
+        this.timeArray_removeAvatarFromScene = new RunTimeArray,
+        this.timeArray_setPosition = new RunTimeArray,
+        this.timeArray_loadMeshes = new RunTimeArray
     }
 }

+ 99 - 78
src/XLightManager.js

@@ -3,50 +3,68 @@ import Logger from "./Logger.js"
 const logger = new Logger('LightManager')
 
 export default class XLightManager {
-    constructor(e) {
-        E(this, "_scene");
-        E(this, "_envTexture");
-        E(this, "_shadowLight");
-        E(this, "_shadowGenerator");
-        E(this, "_avatarShadowMeshMap");
-        E(this, "_cullingShadowObservers");
-        E(this, "sceneManager");
-        this.sceneManager = e,
+    constructor(o) {
+        this.sceneManager = o,
         this._scene = this.sceneManager.Scene,
         this._envTexture = null,
         this.shadowLean = .1;
-        const t = new BABYLON.Vector3(this.shadowLean,-1,0)
-          , r = 1024;
-        this._shadowLight = new BABYLON.DirectionalLight("AvatarLight",t,this._scene),
+        const s = new BABYLON.Vector3(this.shadowLean,-1,0)
+          , c = 1024;
+        this._shadowLight = new BABYLON.DirectionalLight("AvatarLight",s,this._scene),
         this._shadowLight.shadowMaxZ = 5e3,
         this._shadowLight.intensity = 0,
         this.attachLightToCamera(this._shadowLight),
-        this._shadowGenerator = new BABYLON.ShadowGenerator(r,this._shadowLight,!0),
+        this._shadowGenerator = new BABYLON.ShadowGenerator(c,this._shadowLight,!0),
+        this._shadowGenerator.bias = 3e-4,
         this._avatarShadowMeshMap = new Map,
         this._cullingShadowObservers = new Map
     }
-    set shadowLean(e) {
-        e = Math.min(e, 1),
-        e = Math.max(e, -1),
-        this._shadowLight && (this._shadowLight.direction = new BABYLON.Vector3(e,-1,0))
+    set shadowLean(o) {
+        o = Math.min(o, 1),
+        o = Math.max(o, -1),
+        this._shadowLight && (this._shadowLight.direction = new BABYLON.Vector3(o,-1,0))
     }
-    setIBL(e) {
-        return new Promise((t,r)=>{
-            this.sceneManager.urlTransformer(e).then(n=>{
-                var o;
-                if (n == ((o = this._envTexture) == null ? void 0 : o.url))
-                    return t("env set success");
-                this._envTexture != null && this.disposeIBL(),
-                this._envTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(n, this._scene, ".env"),
-                this._scene.environmentTexture = this._envTexture,
+    setIBL(o) {
+        if (this.sceneManager.gl instanceof WebGLRenderingContext)
+            if (o instanceof Array) {
+                let s = "";
+                o.forEach(c=>{
+                    c.endsWith("hdr") && (s = c)
+                }
+                ),
+                s != "" ? o = s : (o = o[0],
+                logger.warn(`[Engine] SetIBL need .hdr in webgl1.0. input has no hdr. Use the first one ${o}`))
+            } else
+                o.endsWith("hdr") == !1 && logger.warn(`[Engine] SetIBL need .hdr in webgl1.0. input is ${o}`);
+        else
+            o instanceof Array && (o = o[0]);
+        return new Promise((s,c)=>{
+            this.sceneManager.urlTransformer(o).then(_=>{
+                var b;
+                if (_ == ((b = this._envTexture) == null ? void 0 : b.url))
+                {
+                    return s("env set success");
+                }
+                this._envTexture != null && this.disposeIBL();
+                o instanceof Array && (o = o[0]);
+                // o.endsWith("hdr") ? (this._envTexture = new HDRCubeTexture(_,this._scene,128,!1,!0,!1,!0),
+                // this._scene.environmentIntensity = 1.5) : this._envTexture = CubeTexture.CreateFromPrefilteredData(_, this._scene, ".env"),
+                if(o.endsWith("hdr")){
+                    this._envTexture = new BABYLON.HDRCubeTexture(_,this._scene,128,!1,!0,!1,!0);
+                    this._scene.environmentIntensity = 1.5;
+                }
+                else{
+                    this._envTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(_, this._scene, ".env");
+                }
+
+                this._scene.environmentTexture = this._envTexture;
                 this._envTexture.onLoadObservable.addOnce(()=>{
-                    t("env set success"),
+                    s("env set success"),
                     logger.info("env set success")
-                }
-                )
+                })
             }
             ).catch(()=>{
-                r("env set fail")
+                c("env set fail")
             }
             )
         }
@@ -58,71 +76,74 @@ export default class XLightManager {
         this._scene.environmentTexture = null,
         logger.info("env dispose success"))
     }
-    removeShadow(e) {
-        var t;
-        if (this._avatarShadowMeshMap.has(e)) {
-            this._avatarShadowMeshMap.delete(e),
-            this._cullingShadowObservers.get(e) && (this._scene.onBeforeRenderObservable.remove(this._cullingShadowObservers.get(e)),
-            this._cullingShadowObservers.delete(e));
-            const r = e.rootNode;
-            r && ((t = this._shadowGenerator) == null || t.removeShadowCaster(r))
+    removeShadow(o) {
+        var s;
+        if (this._avatarShadowMeshMap.has(o)) {
+            this._avatarShadowMeshMap.delete(o),
+            this._cullingShadowObservers.get(o) && (this._scene.onBeforeRenderObservable.remove(this._cullingShadowObservers.get(o)),
+            this._cullingShadowObservers.delete(o));
+            const c = o.rootNode;
+            c && ((s = this._shadowGenerator) == null || s.removeShadowCaster(c))
         } else
             return
     }
-    setShadow(e) {
-        if (this._avatarShadowMeshMap.has(e))
+    enableShadow(o) {
+        this._shadowLight && (this._shadowLight.shadowEnabled = o)
+    }
+    setShadow(o) {
+        if (this._avatarShadowMeshMap.has(o))
             return;
-        e.rootNode && this._avatarShadowMeshMap.set(e, e.rootNode.getChildMeshes());
-        const t = 20
-          , r = 10
-          , n = this.cullingShadow(t, r, e);
-        this._cullingShadowObservers.set(e, n)
+        o.rootNode && this._avatarShadowMeshMap.set(o, o.rootNode.getChildMeshes());
+        const s = 20
+          , c = 10
+          , _ = this.cullingShadow(s, c, o);
+        this._cullingShadowObservers.set(o, _)
     }
-    cullingShadow(e, t, r) {
-        let n = 0;
-        const o = ()=>{
-            var s, l;
-            if (n == t) {
-                const u = this._avatarShadowMeshMap.get(r)
-                  , c = (s = r.rootNode) == null ? void 0 : s.getChildMeshes()
-                  , h = this._scene.activeCamera;
-                u == null || u.forEach(f=>{
-                    var d;
-                    (d = this._shadowGenerator) == null || d.removeShadowCaster(f, !1)
+    cullingShadow(o, s, c) {
+        let _ = 0;
+        const b = ()=>{
+            var j;
+            if (_ == s) {
+                const $ = this._avatarShadowMeshMap.get(c)
+                  , _e = (j = c.rootNode) == null ? void 0 : j.getChildMeshes()
+                  , et = this._scene.activeCamera;
+                $ == null || $.forEach(tt=>{
+                    var rt;
+                    (rt = this._shadowGenerator) == null || rt.removeShadowCaster(tt, !1)
                 }
                 ),
-                c == null || c.forEach(f=>{
-                    var d;
-                    (d = this._shadowGenerator) == null || d.addShadowCaster(f, !1)
+                _e == null || _e.forEach(tt=>{
+                    var rt;
+                    (rt = this._shadowGenerator) == null || rt.addShadowCaster(tt, !1)
                 }
                 ),
-                h && r.rootNode && ((l = r.rootNode.position) == null ? void 0 : l.subtract(h.position).length()) > e && (c == null || c.forEach(f=>{
-                    var d;
-                    (d = this._shadowGenerator) == null || d.removeShadowCaster(f, !1)
+                et && c.rootNode.position.subtract(et.position).length() > o && (_e == null || _e.forEach(tt=>{
+                    var rt;
+                    (rt = this._shadowGenerator) == null || rt.removeShadowCaster(tt, !1)
                 }
                 )),
-                c && this._avatarShadowMeshMap.set(r, c),
-                n = 0
+                _e && this._avatarShadowMeshMap.set(c, _e),
+                _ = 0
             } else
-                n += 1
+                _ += 1
         }
         ;
-        return this._scene.onBeforeRenderObservable.add(o)
+        return this._scene.onBeforeRenderObservable.add(b)
     }
-    attachLightToCamera(e) {
-        const t = e
-          , r = 15
-          , n = ()=>{
-            const o = this._scene.activeCamera;
-            if (o) {
-                const a = t.direction
-                  , s = new BABYLON.Vector3(r * a.x,r * a.y,r * a.z)
-                  , l = o.position;
-                t.position = l.subtract(s)
+    attachLightToCamera(o) {
+        const s = o
+          , c = 15
+          , _ = ()=>{
+            const b = this._scene.activeCamera;
+            if (b) {
+                const k = s.direction
+                  , j = new BABYLON.Vector3(c * k.x,c * k.y,c * k.z)
+                  , $ = b.position;
+                s.position = $.subtract(j)
             }
         }
         ;
-        return t && this._scene.registerBeforeRender(n),
-        n
+        return s && this._scene.registerBeforeRender(_),
+        _
     }
 }

+ 286 - 547
src/XMaterialComponent.js

@@ -2,567 +2,306 @@ import XVideoRawYUV from "./XVideoRawYUV";
 import Logger from "./Logger.js";
 import XMaterialError from "./Error/XMaterialError";
 
-const logger = new Logger("Material");
+const logger = new Logger("XMaterial");
 export default class XMaterialComponent {
-  constructor(sceneManager, t) {
-    this.yuvInfo
-    this._panoInfo
-    this._dynamic_size
-    this._videoTexture
-    this._videoElement
-    this._lowModelShader
-    this._defaultShader
-    this._inputYUV420 = !0
-    this._inputPanoYUV420 = !0
-    this._isUpdateYUV = !0
-
-    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 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)
-    })
-  }
-
-  _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);
-          }
-        );
-      }
+  constructor(o, s) {
+    this._inputYUV420 = !0,
+    this._inputPanoYUV420 = !0,
+    this._isUpdateYUV = !0,
+    this.initMaterial = async()=>new Promise((c,_)=>{
+        this._initDefaultShader(),
+        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,
+        c(!0)
     }
-    // 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);
-    // }
-  }
-
-  _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)
-      );
-  }
-
-  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;
-      }
-
-      let VideoTexture = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)
-      if (VideoTexture != null) {
-        // 更新视频流
-        VideoTexture.update(stream)
-        VideoTexture.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE)
-      }
-
-      //var o, a
-      //(o = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)) == null || o.update(stream),
-      //(a = this._videoRawYUVTexArray.getVideoYUVTex(videosResOriArrayIndex)) == null || a.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE)
+    ),
+    this._initPureVideoContent = c=>{
+        this._inputYUV420 ? 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(c)
+        }
+        )) : (this._videoElement = c.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: c.fov
+            })
+        }
+        ),
+        this._lowModelShader.setTexture("texture_video", this._videoTexture),
+        this._lowModelShader.setFloat("isYUV", 0))
     }
-  }
-
-  _changeVideoRes = (e) => {
-    this._lowModelShader.setTexture(
-      "texture_video",
-      this._videoRawYUVTexArray.getVideoYUVTex(e)
-    );
-  }
-
-  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`
-            )
-          );
-      });
-    }).catch((n) => logger.error(`[Engine] ${n}`))
-  }
-
-  _initDefaultShader = () => {
-    if(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
+    ,
+    this._changePureVideoLowModelShaderCanvasSize = c=>{
+        var $;
+        const _ = c.fov || 50
+          , b = c.width || 720
+          , k = c.height || 1280
+          , j = b / (2 * Math.tan(Math.PI * _ / 360));
+        this.yuvInfo.fov = _,
+        this.yuvInfo.height = k,
+        this.yuvInfo.width = b,
+        ($ = this._lowModelShader) == null || $.setVector3("focal_width_height", new BABYLON.Vector3(j,b,k))
     }
-  }
-
-  _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"],
+    ,
+    this.updateRawYUVData = (c,_,b,k=-1)=>{
+        var j, $;
+        if (!GEngine.engineOption.bDisableCloudRender && (k == -1 && (k = this.yuvInfo.fov),
+        this._isUpdateYUV == !0)) {
+            const _e = {
+                width: _,
+                height: b,
+                fov: k
+            }
+              , et = this._videoRawYUVTexArray.findId(_, b)
+              , tt = this._videoRawYUVTexArray.getCurrentVideoTexId();
+            (tt < 0 || et != tt || _ != this.yuvInfo.width || b != this.yuvInfo.height || k != this.yuvInfo.fov) && (this.yuvInfo.width = _,
+            this.yuvInfo.height = b,
+            this.yuvInfo.fov = k,
+            this._videoRawYUVTexArray.setCurrentVideoTexId(et),
+            this._changeVideoRes(et),
+            this.changeCameraFovWithShaderUpdate(_e),
+            this._scenemanager.yuvInfo = _e),
+            (j = this._videoRawYUVTexArray.getVideoYUVTex(et)) == null || j.update(c),
+            ($ = this._videoRawYUVTexArray.getVideoYUVTex(et)) == null || $.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE)
         }
-      );
-      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()
+    ,
+    this._changeVideoRes = c=>{
+        this._lowModelShader.setTexture("texture_video", this._videoRawYUVTexArray.getVideoYUVTex(c))
+    }
+    ,
+    this.initDynamicData = (c,_,b)=>new Promise((k,j)=>{
+        this.setDynamicSize(c).then($=>{
+            if ($) {
+                for (let _e = 0; _e < c; ++_e)
+                    (et=>{
+                        this.initDynamicTexture(et, _, b),
+                        this.initDynamicShaders(et).then(()=>{
+                            this._updatePanoShaderInput(et)
+                        }
+                        )
+                    }
+                    )(_e);
+                k(!0)
+            } else
+                j(new XMaterialError(`[Engine] DynamicRoomSize (${c}) is too small`))
+        }
         )
-      );
-  }
-
-  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"],
+    }
+    ).catch(k=>logger.error(`[Engine] ${k}`)),
+    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,.5),
+        this._defaultShader.majorUnitFrequency = 1,
+        this._defaultShader.mainColor = new BABYLON.Color3(.6,.6,.6),
+        this._defaultShader.backFaceCulling = !1)
+    }
+    ,
+    this._initPureVideoShader = ()=>{
+        if (this._lowModelShader == null) {
+            const c = 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"]
+            });
+            c.setTexture("shadowSampler", null),
+            c.setMatrix("lightSpaceMatrix", null),
+            c.setFloat("haveShadowLight", 0),
+            c.setTexture("texture_video", null),
+            c.setFloat("isYUV", this._inputYUV420 ? 1 : 0),
+            c.setFloat("fireworkLight", 0),
+            c.setVector3("fireworkLightPosition", new BABYLON.Vector3(0,0,0)),
+            c.setVector3("focal_width_height", new BABYLON.Vector3(772.022491,720,1280)),
+            c.backFaceCulling = !1,
+            this._lowModelShader = c
         }
-      );
-      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() {
-    this._isUpdateYUV = !1;
-  }
-  allowYUVUpdate() {
-    this._isUpdateYUV = !0;
-  }
-  setPanoInfo(e) {
-    this._panoInfo = e;
-  }
-  _prepareRender(focal_width_height) {
-    if (focal_width_height) {
-      this._initPureVideoContent(focal_width_height);
-      this._updatePureVideoShaderInput();
     }
-  }
-  getPureVideoShader() {
-    return this._lowModelShader;
-  }
-  getDefaultShader() {
-    return this._defaultShader;
-  }
-  updatePanoPartYUV(e, t, r) {
-    const n = t.subarray(0, r.width * r.height),
-      o = t.subarray(r.width * r.height, r.width * r.height * 1.25),
-      a = t.subarray(r.width * r.height * 1.25),
-      s = this._panoInfo.width,
-      l = this._panoInfo.height;
-    if (this._dynamic_textures[e] != null) {
-      const u = this._dynamic_textures[e].getInternalTexture();
-      if (u != null && u != null) {
-        const c = this.engine._getTextureTarget(u);
-        this.engine._bindTextureDirectly(c, u, !0),
-          this.engine.updateTextureData(
-            u,
-            n,
-            r.startX,
-            l * 1.5 - r.startY - r.height,
-            r.width,
-            r.height
-          ),
-          this.engine.updateTextureData(
-            u,
-            o,
-            r.startX * 0.5,
-            (l - r.startY - r.height) * 0.5,
-            r.width * 0.5 - 1,
-            r.height * 0.5 - 1
-          ),
-          this.engine.updateTextureData(
-            u,
-            a,
-            r.startX * 0.5 + s * 0.5,
-            (l - r.startY - r.height) * 0.5,
-            r.width * 0.5,
-            r.height * 0.5
-          ),
-          this.engine._bindTextureDirectly(c, null);
-      }
+    ,
+    this.setDynamicSize = c=>new Promise((_,b)=>{
+        c >= 1 && c <= 100 ? (this._dynamic_size = c,
+        _(!0)) : (this._dynamic_size = 1,
+        _(!1))
     }
-  }
-  changePanoImg(e, t) {
-    if (
-      (logger.info(
-        `[Engine] changePanoImg, id=${e}, pose=${t.pose.position.x},${t.pose.position.y},${t.pose.position.z}`
-      ),
-        !this._isInDynamicRange(e))
-    )
-      return (
-        logger.error(
-          `[Engine] ${e} is bigger than dynamic size set in PanoInfo`
-        ),
-        Promise.reject(
-          new XMaterialError(
-            `[Engine] ${e} is bigger than dynamic size set in PanoInfo`
-          )
-        )
-      );
-    const r = ue4Position2Xverse(t.pose.position);
-    return (
-      r &&
-      (this._dynamic_babylonpose[e] = {
-        position: r,
-      }),
-      new Promise((n, o) => {
-        try {
-          typeof t.data == "string"
-            ? (this.setPanoYUV420(!1),
-              this._dynamic_textures[e].updateURL(t.data, null, () => {
-                this._dynamic_textures[e].updateSamplingMode(
-                  BABYLON.Texture.NEAREST_SAMPLINGMODE
-                );
-              }))
-            : (this.isPanoYUV420() == !1 &&
-              this.initDynamicTexture(
-                e,
-                this._panoInfo.width,
-                this._panoInfo.height
-              ),
-              this.setPanoYUV420(!0),
-              this._dynamic_textures[e].update(t.data),
-              this._dynamic_textures[e].updateSamplingMode(
-                BABYLON.Texture.NEAREST_SAMPLINGMODE
-              )),
-            n(this);
-        } catch (a) {
-          o(new XMaterialError(`[Engine] ChangePanoImg Error! ${a}`));
+    ),
+    this._isInDynamicRange = c=>c < this._dynamic_size && c >= 0,
+    this.initDynamicTexture = (c,_,b)=>{
+        this._isInDynamicRange(c) && (this._dynamic_textures[c] != null && (this._dynamic_textures[c].dispose(),
+        this._dynamic_textures[c] = null),
+        this._dynamic_textures[c] = new BABYLON.RawTexture(null,_,b * 1.5,BABYLON.Engine.TEXTUREFORMAT_LUMINANCE,this.scene,!1,!0,BABYLON.Texture.NEAREST_SAMPLINGMODE,BABYLON.Engine.TEXTURETYPE_UNSIGNED_BYTE),
+        this._dynamic_textures[c].name = "Pano_Dynamic_" + c + "_" + Date.now())
+    }
+    ,
+    this.initDynamicShaders = c=>(logger.info("[Engine] Material init dynamic shader."),
+    new Promise((_,b)=>{
+        this._dynamic_shaders[c] != null && this._dynamic_shaders[c].dispose();
+        const k = new BABYLON.ShaderMaterial("Pano_Shader_" + c,this.scene,{
+            vertexSource: panoVertex,
+            fragmentSource: panoFragment
+        },{
+            attributes: ["uv", "position", "world0", "world1", "world2", "world3"],
+            uniforms: ["view", "projection", "worldViewProjection", "world"],
+            defines: ["#define SHADOWFULLFLOAT"]
+        });
+        k.setTexture("texture_pano", null),
+        k.setVector3("centre_pose", new BABYLON.Vector3(0,0,0)),
+        k.setFloat("isYUV", this._inputPanoYUV420 ? 1 : 0),
+        k.setTexture("shadowSampler", null),
+        k.setMatrix("lightSpaceMatrix", null),
+        k.setFloat("haveShadowLight", 0),
+        k.setFloat("fireworkLight", 0),
+        k.setVector3("fireworkLightPosition", new BABYLON.Vector3(0,0,0)),
+        k.backFaceCulling = !1,
+        this._dynamic_shaders[c] = k,
+        _(!0)
+    }
+    )),
+    this._scenemanager = o,
+    this.scene = o.Scene,
+    this.engine = this.scene.getEngine(),
+    this.shaderMode = 1,
+    this._dynamic_textures = [],
+    this._dynamic_shaders = [],
+    this._dynamic_babylonpose = [],
+    this._videoRawYUVTexArray = new XVideoRawYUV(this.scene,s.videoResOriArray),
+    this.shaderMode = s.shaderMode,
+    s.yuvInfo != null && (this.yuvInfo = s.yuvInfo),
+    s.panoInfo != null && this.setPanoInfo(s.panoInfo)
+}
+stopYUVUpdate() {
+    this._isUpdateYUV = !1
+}
+allowYUVUpdate() {
+    this._isUpdateYUV = !0
+}
+setPanoInfo(o) {
+    this._panoInfo = o
+}
+_prepareRender(o) {
+    o && (this._initPureVideoContent(o),
+    this._updatePureVideoShaderInput())
+}
+changeCameraFovWithShaderUpdate(o) {
+    this._changePureVideoLowModelShaderCanvasSize(o),
+    this._scenemanager.cameraComponent.cameraFovChange(o)
+}
+getPureVideoShader() {
+    return this._lowModelShader
+}
+getDefaultShader() {
+    return this._defaultShader
+}
+updatePanoPartYUV(o, s, c) {
+    const _ = s.subarray(0, c.width * c.height)
+      , b = s.subarray(c.width * c.height, c.width * c.height * 1.25)
+      , k = s.subarray(c.width * c.height * 1.25)
+      , j = this._panoInfo.width
+      , $ = this._panoInfo.height;
+    if (this._dynamic_textures[o] != null) {
+        const _e = this._dynamic_textures[o].getInternalTexture();
+        if (_e != null && _e != null) {
+            const et = this.engine._getTextureTarget(_e);
+            this.engine._bindTextureDirectly(et, _e, !0),
+            this.engine.updateTextureData(_e, _, c.startX, $ * 1.5 - c.startY - c.height, c.width, c.height),
+            this.engine.updateTextureData(_e, b, c.startX * .5, ($ - c.startY - c.height) * .5, c.width * .5 - 1, c.height * .5 - 1),
+            this.engine.updateTextureData(_e, k, c.startX * .5 + j * .5, ($ - c.startY - c.height) * .5, c.width * .5, c.height * .5),
+            this.engine._bindTextureDirectly(et, null)
         }
-      }).then(
-        (n) => (
-          t.fov != null &&
-          this._scenemanager.cameraComponent.changeCameraFov(
-            (t.fov * Math.PI) / 180
-          ),
-          this._dynamic_shaders[e].setFloat(
-            "isYUV",
-            this._inputPanoYUV420 ? 1 : 0
-          ),
-          this._dynamic_shaders[e].setTexture(
-            "texture_pano",
-            this._dynamic_textures[e]
-          ),
-          this._dynamic_shaders[e].setVector3(
-            "centre_pose",
-            this._dynamic_babylonpose[e].position
-          ),
-          !0
-        )
-      )
-    );
-  }
-  setYUV420(e) {
-    this._inputYUV420 = e;
-  }
-  isYUV420() {
-    return this._inputYUV420;
-  }
-  setPanoYUV420(e) {
-    this._inputPanoYUV420 = e;
-  }
-  isPanoYUV420() {
-    return this._inputPanoYUV420;
-  }
-  getDynamicShader(e) {
-    return this._dynamic_shaders[e];
-  }
-  _updatePureVideoShaderInput() {
-    /*
-        var e, t, r, n, o, a, s, l, u, c;
-
-        if(this.scene.getLightByName("AvatarLight")){
-            (e = this._lowModelShader) == null || e.setFloat("haveShadowLight", 1);
-
-            n = this._lowModelShader
-            if(n != null){
-                t = this.scene.getLightByName("AvatarLight")
-                if(t == null){
-                    r = void 0
-                }
-                else{
-                    r = t.getShadowGenerator()
-                }
-
-                if(r == null){
-                    n.setTexture("shadowSampler",void 0)
-                }
-                else{
-                    n.setTexture("shadowSampler",r.getShadowMapForRendering())
-                }
-            }
-
-            //(n = this._lowModelShader) == null || n.setTexture("shadowSampler", (r = (t = this.scene.getLightByName("AvatarLight")) == null ? void 0 : t.getShadowGenerator()) == null ? void 0 : r.getShadowMapForRendering());
-
-            s = this._lowModelShader
-            if(s != null){
-                o = this.scene.getLightByName("AvatarLight")
-                if(o == null){
-                    a = void 0
-                }
-                else{
-                    a = o.getShadowGenerator()
-                }
-
-                if(a == null){
-                    s.setMatrix("lightSpaceMatrix",void 0)
-                }
-                else{
-                    s.setMatrix("lightSpaceMatrix",a.getTransformMatrix())
-                }
+    }
+}
+changePanoImg(o, s) {
+    if (logger.info(`[Engine] changePanoImg, id=${o}, pose=${s.pose.position.x},${s.pose.position.y},${s.pose.position.z}`),
+    !this._isInDynamicRange(o))
+        return logger.error(`[Engine] ${o} is bigger than dynamic size set in PanoInfo`),
+        Promise.reject(new XMaterialError(`[Engine] ${o} is bigger than dynamic size set in PanoInfo`));
+    const c = ue4Position2Xverse(s.pose.position);
+    return c && (this._dynamic_babylonpose[o] = {
+        position: c
+    }),
+    new Promise((_,b)=>{
+        try {
+            typeof s.data == "string" ? (this.setPanoYUV420(!1),
+            this._dynamic_textures[o].updateURL(s.data, null, ()=>{
+                this._dynamic_textures[o].updateSamplingMode(BABYLON.Texture.NEAREST_SAMPLINGMODE)
             }
-            //(s = this._lowModelShader) == null || s.setMatrix("lightSpaceMatrix", (a = (o = this.scene.getLightByName("AvatarLight")) == null ? void 0 : o.getShadowGenerator()) == null ? void 0 : a.getTransformMatrix())
+            )) : (this.isPanoYUV420() == !1 && this.initDynamicTexture(o, this._panoInfo.width, this._panoInfo.height),
+            this.setPanoYUV420(!0),
+            this._dynamic_textures[o].update(s.data),
+            this._dynamic_textures[o].updateSamplingMode(BABYLON.Texture.NEAREST_SAMPLINGMODE)),
+            _(this)
+        } catch (k) {
+            b(new XMaterialError(`[Engine] ChangePanoImg Error! ${k}`))
         }
-        else{
-            (l = this._lowModelShader) == null || l.setTexture("shadowSampler", this._videoTexture);
-            (u = this._lowModelShader) == null || u.setMatrix("lightSpaceMatrix", new Matrix);
-            (c = this._lowModelShader) == null || c.setFloat("haveShadowLight", 0);
-        }
-        */
-
-    let lowModelShader = this._lowModelShader;
-    if (lowModelShader != null) {
-      if (this.scene.getLightByName("AvatarLight")) {
-        lowModelShader.setFloat("haveShadowLight", 1);
-
-        let avatarLight = this.scene.getLightByName("AvatarLight");
-        let shadow = void 0;
-        if (avatarLight != null) {
-          shadow = avatarLight.getShadowGenerator();
-        }
-
-        if (shadow == null) {
-          lowModelShader.setTexture("shadowSampler", void 0);
-          lowModelShader.setMatrix("lightSpaceMatrix", void 0);
-        } else {
-          lowModelShader.setTexture(
-            "shadowSampler",
-            shadow.getShadowMapForRendering()
-          );
-          lowModelShader.setMatrix(
-            "lightSpaceMatrix",
-            shadow.getTransformMatrix()
-          );
-        }
-      } else {
-        lowModelShader.setTexture("shadowSampler", this._videoTexture);
-        lowModelShader.setMatrix("lightSpaceMatrix", new Matrix());
-        lowModelShader.setFloat("haveShadowLight", 0);
-      }
     }
-
-    if (this.scene.getLightByName("fireworkLight")) {
-      this.scene.registerBeforeRender(() => {
-        this._lowModelShader.setFloat(
-          "fireworkLight",
-          this.scene.getLightByName("fireworkLight").getScaledIntensity()
-        );
-        var fireworkLight = this.scene.getLightByName("fireworkLight");
-        if (fireworkLight == null) {
-          this._lowModelShader.setVector3("fireworkLightPosition", void 0);
-        } else {
-          this._lowModelShader.setVector3(
-            "fireworkLightPosition",
-            fireworkLight.position
-          );
+    ).then(_=>(s.fov != null && this._scenemanager.cameraComponent.changeCameraFov(s.fov * Math.PI / 180),
+    this._dynamic_shaders[o].setFloat("isYUV", this._inputPanoYUV420 ? 1 : 0),
+    this._dynamic_shaders[o].setTexture("texture_pano", this._dynamic_textures[o]),
+    this._dynamic_shaders[o].setVector3("centre_pose", this._dynamic_babylonpose[o].position),
+    !0))
+}
+setYUV420(o) {
+    this._inputYUV420 = o
+}
+isYUV420() {
+    return this._inputYUV420
+}
+setPanoYUV420(o) {
+    this._inputPanoYUV420 = o
+}
+isPanoYUV420() {
+    return this._inputPanoYUV420
+}
+getDynamicShader(o) {
+    return this._dynamic_shaders[o]
+}
+_updatePureVideoShaderInput() {
+    var o, s, c, _, b, k, j, $, _e, et, tt, rt;
+    if (this.scene.getLightByName("AvatarLight") ? ((o = this.scene.getLightByName("AvatarLight")) != null && o.shadowEnabled ? (s = this._lowModelShader) == null || s.setFloat("haveShadowLight", 1) : (c = this._lowModelShader) == null || c.setFloat("haveShadowLight", 0),
+    (k = this._lowModelShader) == null || k.setTexture("shadowSampler", (b = (_ = this.scene.getLightByName("AvatarLight")) == null ? void 0 : _.getShadowGenerator()) == null ? void 0 : b.getShadowMapForRendering()),
+    (_e = this._lowModelShader) == null || _e.setMatrix("lightSpaceMatrix", ($ = (j = this.scene.getLightByName("AvatarLight")) == null ? void 0 : j.getShadowGenerator()) == null ? void 0 : $.getTransformMatrix())) : ((et = this._lowModelShader) == null || et.setTexture("shadowSampler", this._videoRawYUVTexArray.getVideoYUVTex(0)),
+    (tt = this._lowModelShader) == null || tt.setMatrix("lightSpaceMatrix", new BABYLON.Matrix),
+    (rt = this._lowModelShader) == null || rt.setFloat("haveShadowLight", 0)),
+    this.scene.getLightByName("fireworkLight"))
+        this.scene.registerBeforeRender(()=>{
+            var it;
+            this._lowModelShader.setFloat("fireworkLight", this.scene.getLightByName("fireworkLight").getScaledIntensity()),
+            this._lowModelShader.setVector3("fireworkLightPosition", (it = this.scene.getLightByName("fireworkLight")) == null ? void 0 : it.position)
         }
-        //this._lowModelShader.setVector3("fireworkLightPosition", (h = this.scene.getLightByName("fireworkLight")) == null ? void 0 : h.position);
-      });
-    } else {
-      const pointLight = new BABYLON.PointLight(
-        "fireworkLight",
-        new BABYLON.Vector3(0, 0, 0),
-        this.scene
-      );
-      pointLight.intensity = 0;
-    }
-  }
-
-  _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
-      }
+        );
+    else {
+        const it = new BABYLON.PointLight("fireworkLight",new BABYLON.Vector3(0,0,0),this.scene);
+        it.intensity = 0
     }
-  }
+}
+_updatePanoShaderInput(o) {
+    var s, c, _, b, k, j, $, _e, et, tt, rt, it;
+    if (this._isInDynamicRange(o))
+        if (this.scene.getLightByName("AvatarLight") ? ((s = this.scene.getLightByName("AvatarLight")) != null && s.shadowEnabled ? (c = this._dynamic_shaders[o]) == null || c.setFloat("haveShadowLight", 1) : (_ = this._dynamic_shaders[o]) == null || _.setFloat("haveShadowLight", 0),
+        (j = this._dynamic_shaders[o]) == null || j.setTexture("shadowSampler", (k = (b = this.scene.getLightByName("AvatarLight")) == null ? void 0 : b.getShadowGenerator()) == null ? void 0 : k.getShadowMapForRendering()),
+        (et = this._dynamic_shaders[o]) == null || et.setMatrix("lightSpaceMatrix", (_e = ($ = this.scene.getLightByName("AvatarLight")) == null ? void 0 : $.getShadowGenerator()) == null ? void 0 : _e.getTransformMatrix())) : ((tt = this._lowModelShader) == null || tt.setTexture("shadowSampler", this._videoRawYUVTexArray.getVideoYUVTex(0)),
+        (rt = this._lowModelShader) == null || rt.setMatrix("lightSpaceMatrix", new BABYLON.Matrix),
+        (it = this._lowModelShader) == null || it.setFloat("haveShadowLight", 0)),
+        this.scene.getLightByName("fireworkLight"))
+            this.scene.registerBeforeRender(()=>{
+                var nt;
+                this._dynamic_shaders[o].setFloat("fireworkLight", this.scene.getLightByName("fireworkLight").getScaledIntensity()),
+                this._dynamic_shaders[o].setVector3("fireworkLightPosition", (nt = this.scene.getLightByName("fireworkLight")) == null ? void 0 : nt.position)
+            }
+            );
+        else {
+            const nt = new BABYLON.PointLight("fireworkLight",new BABYLON.Vector3(0,0,0),this.scene);
+            nt.intensity = 0
+        }
+}
 }

+ 74 - 76
src/XParticleManager.js

@@ -1,112 +1,110 @@
-class XParticleManager{
-    constructor(e) {
-        E(this, "_scene");
-        E(this, "_particles");
-        E(this, "_light");
-        E(this, "load", (e,t,r)=>new Promise(n=>{
-            ParticleSystemSet.BaseAssetsUrl = e;
-            const o = new XMLHttpRequest;
-            o.open("get", e + "/" + t),
-            o.send(null),
-            o.onload = ()=>{
-                if (o.status == 200) {
-                    const a = JSON.parse(o.responseText);
-                    let s = null;
-                    if (Object.keys(a).find(l=>l == "systems") == null) {
-                        const l = ParticleSystem.Parse(a, this._scene, e);
-                        s = new ParticleSystemSet,
-                        s.systems.push(l)
+export default class XParticleManager{
+    constructor(d) {
+        if (this.load = (o,s,c)=>new Promise(_=>{
+            ParticleSystemSet.BaseAssetsUrl = o,
+            ParticleHelper.BaseAssetsUrl = o;
+            const b = new XMLHttpRequest;
+            b.open("get", o + "/" + s),
+            b.send(null),
+            b.onload = ()=>{
+                if (b.status == 200) {
+                    const k = JSON.parse(b.responseText);
+                    let j = null;
+                    if (Object.keys(k).find($=>$ == "systems") == null) {
+                        const $ = ParticleSystem.Parse(k, this._scene, o);
+                        j = new ParticleSystemSet,
+                        j.systems.push($)
                     } else
-                        s = ParticleSystemSet.Parse(a, this._scene, !1);
-                    n(s)
+                        j = ParticleSystemSet.Parse(k, this._scene, !1);
+                    _(j)
                 }
             }
         }
-        ));
-        E(this, "get", e=>this._particles.get(e));
-        E(this, "start", e=>{
-            const t = this._particles.get(e);
-            t && t.start()
+        ),
+        this.get = o=>this._particles.get(o),
+        this.start = o=>{
+            const s = this._particles.get(o);
+            s && s.start()
         }
-        );
-        E(this, "stop", e=>{
-            var r;
-            const t = ((r = this._particles.get(e)) == null ? void 0 : r.systems) || [];
-            for (let n = 0; n < t.length; n++)
-                t[n].stop()
+        ,
+        this.stop = o=>{
+            var c;
+            const s = ((c = this._particles.get(o)) == null ? void 0 : c.systems) || [];
+            for (let _ = 0; _ < s.length; _++)
+                s[_].stop()
         }
-        );
-        E(this, "remove", e=>{
-            const t = this._particles.get(e);
-            t && t.dispose()
+        ,
+        this.remove = o=>{
+            const s = this._particles.get(o);
+            s && s.dispose()
         }
-        );
-        E(this, "setParticlePosition", (e,t)=>{
-            const r = this._particles.get(e);
-            r && (r.emitterNode = t)
+        ,
+        this.setParticlePosition = (o,s)=>{
+            const c = this._particles.get(o);
+            c && (c.emitterNode = s)
         }
-        );
-        E(this, "setParticleScalingInPlace", (e,t)=>{
-            const r = this._particles.get(e);
-            r == null || r.systems.forEach(n=>{
-                de.scalingInPlace(n, t)
+        ,
+        this.setParticleScalingInPlace = (o,s)=>{
+            const c = this._particles.get(o);
+            c == null || c.systems.forEach(_=>{
+                _XParticleManager.scalingInPlace(_, s)
             }
             )
         }
-        );
-        if (this._scene = e,
+        ,
+        this._scene = d,
         this._particles = new Map,
         this._light = null,
         this._scene.getLightByName("fireworkLight"))
             this._light = this._scene.getLightByName("fireworkLight");
         else {
-            const t = new PointLight("fireworkLight",new BABYLON.Vector3(0,0,0),e);
-            t.intensity = 0,
-            this._light = t
+            const o = new BABYLON.PointLight("fireworkLight",new BABYLON.Vector3(0,0,0),d);
+            o.intensity = 0,
+            this._light = o
         }
     }
-    _flashBang(e=200) {
-        const t = this._scene.getLightByName("fireworkLight");
-        t.intensity = 1,
+    _flashBang(d=200) {
+        const o = this._scene.getLightByName("fireworkLight");
+        o.intensity = 1,
         setTimeout(()=>{
-            t.intensity = 0
+            o.intensity = 0
         }
-        , e)
+        , d)
     }
 }
 ;
 
-E(XParticleManager, "disposeParticleSysSet", e=>{
-    !e.systems || (e.systems.forEach(t=>{
-        de.disposeParticleSystem(t)
+XParticleManager.disposeParticleSysSet = d=>{
+    !d.systems || (d.systems.forEach(o=>{
+        _XParticleManager.disposeParticleSystem(o)
     }
     ),
-    e.dispose())
+    d.dispose())
 }
-),
-E(XParticleManager, "disposeParticleSystem", e=>{
-    e.particleSystem && (e = e.particleSystem),
-    e.subEmitters && e.subEmitters.forEach(t=>{
-        t instanceof Array ? t.forEach(r=>{
-            de.disposeParticleSystem(r)
+;
+XParticleManager.disposeParticleSystem = d=>{
+    d.particleSystem && (d = d.particleSystem),
+    d.subEmitters && d.subEmitters.forEach(o=>{
+        o instanceof Array ? o.forEach(s=>{
+            _XParticleManager.disposeParticleSystem(s)
         }
-        ) : de.disposeParticleSystem(t)
+        ) : _XParticleManager.disposeParticleSystem(o)
     }
     ),
-    e.dispose()
+    d.dispose()
 }
-),
-E(XParticleManager, "scalingInPlace", (e,t)=>{
-    e.getClassName() === "ParticleSystem" && (e.minSize *= t,
-    e.maxSize *= t,
-    e.subEmitters != null && e.subEmitters.forEach(r=>{
-        r instanceof SubEmitter && de.scalingInPlace(r.particleSystem, t),
-        r instanceof ParticleSystem && de.scalingInPlace(r, t),
-        r instanceof Array && r.forEach(n=>{
-            de.scalingInPlace(n.particleSystem, t)
+;
+XParticleManager.scalingInPlace = (d,o)=>{
+    d.getClassName() === "ParticleSystem" && (d.minSize *= o,
+    d.maxSize *= o,
+    d.subEmitters != null && d.subEmitters.forEach(s=>{
+        s instanceof SubEmitter && _XParticleManager.scalingInPlace(s.particleSystem, o),
+        s instanceof ParticleSystem && _XParticleManager.scalingInPlace(s, o),
+        s instanceof Array && s.forEach(c=>{
+            _XParticleManager.scalingInPlace(c.particleSystem, o)
         }
         )
     }
     ))
 }
-);
+;

+ 10 - 10
src/XRain.js

@@ -2,17 +2,17 @@
 import XSubSequence from "./XSubSequence.js"
 
 export default class XRain extends XSubSequence {
-    constructor(e, t, r) {
-        super(e, t, r);
+    constructor(o, s, c) {
+        super(o, s, c),
         this.onLoadedObserverable.addOnce(()=>{
-            this._particleGroups.forEach(n=>{
-                const o = n.systems[0];
-                o.getClassName() == "ParticleSystem" && (o.startPositionFunction = function(a, s) {
-                    const u = 2 * Math.random() * Math.PI
-                      , c = Math.random() * 15 * Math.sin(u)
-                      , h = this.minEmitBox.y
-                      , f = Math.random() * 15 * Math.cos(u);
-                      BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(c, h, f, a, s)
+            this._particleGroups.forEach(_=>{
+                const b = _.systems[0];
+                b.getClassName() == "ParticleSystem" && (b.startPositionFunction = function(k, j) {
+                    const _e = 2 * Math.random() * Math.PI
+                      , et = Math.random() * 15 * Math.sin(_e)
+                      , tt = this.minEmitBox.y
+                      , rt = Math.random() * 15 * Math.cos(_e);
+                    BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(et, tt, rt, k, j)
                 }
                 )
             }

+ 269 - 261
src/XSceneManager.js

@@ -9,171 +9,152 @@ import XBillboardManager from "./XBillboardManager.js"
 import XLightManager from "./XLightManager.js"
 import XEngineRunTimeStats from "./XEngineRunTimeStats.js"
 import EShaderMode from "./enum/EShaderMode.js"
-import defaultLog from "./defaultLog.js"
 import Logger from "./Logger.js"
+import XPlayerController from "./XPlayerController.js"
 
-const logger = new Logger('SceneManager')
-
-const getAlphaWidthMap = (i,e)=>{
-    const t = new BABYLON.DynamicTexture("test",3,e)
-      , r = new Map;
-    for (let n = 32; n < 127; n++) {
-        const o = String.fromCodePoint(n)
-          , a = 2 + "px " + i;
-        t.drawText(o, null, null, a, "#000000", "#ffffff", !0);
-        const s = t.getContext();
-        s.font = a;
-        const l = s.measureText(o).width;
-        r.set(n, l)
-    }
-    return t.dispose(),
-    r
-}
-
+const logger = new Logger('XSceneManager')
 export default class XSceneManager {
-    constructor(canvas, options) {
-        this.cameraParam
-        this.shaderMode
-        this.panoInfo
-        this._forceKeepVertical = !1
-        this._currentShader
-        this._renderStatusCheckCount = 0
-        this._renderStatusNotChecktCount = 0
-        this._nonlinearCanvasResize = !1
-        this._bChangeEngineSize = !0
-        this._skytv
-        this._mv = []
-        this._backgroundImg
-
-        this.engine = new BABYLON.Engine(canvas, !0, {
+    
+    constructor(o, s, c, _, b) {
+        this._forceKeepVertical = !1,
+        this._renderStatusCheckCount = 0,
+        this._renderStatusNotChecktCount = 0,
+        this._nonlinearCanvasResize = !1,
+        this._bChangeEngineSize = !0,
+        this._mv = [],
+        this.uploadHardwareSystemInfo = ()=>{
+            const et = this.statisticComponent.getHardwareRenderInfo()
+              , tt = this.statisticComponent.getSystemInfo()
+              , rt = {
+                driver: tt.driver,
+                vender: tt.vender,
+                webgl: tt.version,
+                os: tt.os
+            };
+            logger.warn(JSON.stringify(et)),
+            logger.warn(JSON.stringify(rt))
+        }
+        ,
+        this.addNewLowPolyMesh = async(et,tt)=>(this._currentShader == null && await this.initSceneManager(),
+        this._lowpolyManager.addNewLowPolyMesh(et, tt, this._currentShader)),
+        this.initSceneManager = async()=>(await this._materialManager.initMaterial(),
+        this.applyShader()),
+        this.registerAfterRender = ()=>{
+            var et;
+            if (this._forceKeepVertical) {
+                const tt = this.canvas.width
+                  , rt = this.canvas.height;
+                let it = 0
+                  , nt = [[0, 0, 0, 0], [0, 0, 0, 0]];
+                if (((et = this._cameraManager.MainCamera) == null ? void 0 : et.fovMode) === BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED ? (it = Math.ceil((rt - this._yuvInfo.height * tt / this._yuvInfo.width) / 2),
+                nt = [[0, 0, tt, it], [0, rt - it, tt, it]]) : (it = Math.ceil((tt - this._yuvInfo.width * rt / this._yuvInfo.height) / 2),
+                nt = [[0, 0, it, rt], [tt - it, 0, it, rt]]),
+                it > 0) {
+                    this.gl.enable(this.gl.SCISSOR_TEST);
+                    for (let at = 0; at < nt.length; ++at)
+                        this.gl.scissor(nt[at][0], nt[at][1], nt[at][2], nt[at][3]),
+                        this.gl.clearColor(0, 0, 0, 1),
+                        this.gl.clear(this.gl.COLOR_BUFFER_BIT);
+                    this.gl.disable(this.gl.SCISSOR_TEST)
+                }
+            }
+        }
+        ,
+        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 k = s.disableWebGL2;
+        c || (c = new BABYLON.Engine(o,!0,{
             preserveDrawingBuffer: !0,
             stencil: !0,
-            disableWebGL2Support: /iphone|ipad/gi.test(window.navigator.userAgent) || options.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(),
-        this.engine.enableOfflineSupport = !1,
-        this.engine.doNotHandleContextLost = !0,
-        this.scene.clearCachedVertexData(),
-        this.scene.cleanCachedTextureBuffer(),
-        debugMode && this.scene.debugLayer.show({ embedMode: true, }),    // BABYLON调试工具栏
-
-        this.urlTransformer = options.urlTransformer || (s=>Promise.resolve(s)),
-        options.logger && defaultLog.setLogger(options.logger),
-
-        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,
-        options.forceKeepVertical && (this._forceKeepVertical = options.forceKeepVertical),
-        options.panoInfo && (this.panoInfo = options.panoInfo),
-        options.shaderMode && (this.shaderMode = options.shaderMode),
-        options.yuvInfo ? this._yuvInfo = options.yuvInfo : this._yuvInfo = {
-            width: options.videoResOriArray[0].width,
-            height: options.videoResOriArray[0].height,
+            disableWebGL2Support: k
+        },!0)),
+        _ || (_ = new BABYLON.Scene(c)),
+        this.scene = _,
+        this.engine = c,
+        this.canvas = o;
+        this.scene.clearColor = new BABYLON.Color4(.7,.7,.7,1);
+        this.engine.getCaps().parallelShaderCompile = void 0;
+        this._initEngineScaleNumber = this.engine.getHardwareScalingLevel();
+        this.engine.enableOfflineSupport = !1;
+        this.engine.doNotHandleContextLost = !0;
+        GEngine.engineOption.onFeatureSwitchChanged.add(et=>{
+            this.scene.meshes.forEach(tt=>{
+                (tt.xtype == "tv" || tt.xtype == "breathpoint" || tt.xtype == "decal" || tt.xtype == "cgplane") && (tt.visibility = !GEngine.engineOption.bDisableLocalRender,
+                tt.isVisible = !GEngine.engineOption.bDisableLocalRender),
+                tt.xtype == "XStaticMesh" && (tt.visibility = !GEngine.engineOption.bDisableCloudRender,
+                tt.isVisible = !GEngine.engineOption.bDisableCloudRender)
+            }
+            )
+        }
+        );
+        this.scene.clearCachedVertexData();
+        this.scene.cleanCachedTextureBuffer();
+        this.urlTransformer = s.urlTransformer || (et=>Promise.resolve(et));
+        //s.logger && Logger.setLogger(s.logger),
+        this.gl = o.getContext("webgl2", {
+            preserveDrawingBuffer: !0
+        }) || o.getContext("webgl", {
+            preserveDrawingBuffer: !0
+        }) || o.getContext("experimental-webgl", {
+            preserveDrawingBuffer: !0
+        });
+        this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1);
+        this._currentPanoId = 0;
+        s.forceKeepVertical != null && (this._forceKeepVertical = s.forceKeepVertical);
+        s.panoInfo != null && (this.panoInfo = s.panoInfo);
+        s.shaderMode != null && (this.shaderMode = s.shaderMode);
+        s.yuvInfo != null ? this._yuvInfo = s.yuvInfo : this._yuvInfo = {
+            width: s.videoResOriArray[0].width,
+            height: s.videoResOriArray[0].height,
             fov: 50
-        },
-        options.cameraParam && (this.cameraParam = options.cameraParam),
-        options.nonlinearCanvasResize && (this._nonlinearCanvasResize = options.nonlinearCanvasResize),
-
+        };
+        s.cameraParam != null && (this.cameraParam = s.cameraParam);
+        s.nonlinearCanvasResize != null && (this._nonlinearCanvasResize = s.nonlinearCanvasResize);
         this._cameraManager = new XCameraComponent(this.canvas,this.scene,{
             cameraParam: this.cameraParam,
             yuvInfo: this._yuvInfo,
             forceKeepVertical: this._forceKeepVertical
-        }),
-        this._lowpolyManager = new XStaticMeshComponent(this),
+        });
+        this._lowpolyManager = new XStaticMeshComponent(this);
         this._materialManager = new XMaterialComponent(this,{
-            videoResOriArray: options.videoResOriArray,
+            videoResOriArray: s.videoResOriArray,
             yuvInfo: this._yuvInfo,
             panoInfo: this.panoInfo,
             shaderMode: this.shaderMode
-        }),
-        this._statisticManager = new XStats(this),
-        this._breathPointManager = new XBreathPointManager(this),
-        this._decalManager = new XDecalManager(this),
-        this._avatarManager = new XAvatarManager(this),
-        this._billboardManager = new XBillboardManager(this),
-        this.billboardComponent.loadBackGroundTexToIDB(),
-        this._lightManager = new XLightManager(this),
-        this.postprocessing(),
+        });
+        this._statisticManager = new XStats(this);
+        this._breathPointManager = new XBreathPointManager(this);
+        this._decalManager = new XDecalManager(this);
+        this._avatarManager = new XAvatarManager(this);
+        this._billboardManager = new XBillboardManager(this);
+        this.billboardComponent.loadBackGroundTexToIDB();
+        let j = !1
+          , $ = !1;
+        s.disableLight != null && (j = s.disableLight),
+        s.disablePostprocess != null && ($ = s.disablePostprocess),
+        j || (this._lightManager = new XLightManager(this)),
+        $ || 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 * (b || 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.parse(JSON.stringify(e))),
-        logger.warn(JSON.parse(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,
@@ -181,9 +162,13 @@ export default class XSceneManager {
             fov: -1
         }
     }
-    set yuvInfo(e) {
-        this.getCurrentShaderMode() == 1 && (this._yuvInfo = e,
-        this._cameraManager.cameraFovChange(e))
+    set yuvInfo(o) {
+        this.getCurrentShaderMode() == 1 && (this._yuvInfo = o,
+        this._cameraManager.cameraFovChange(o))
+    }
+    get playerController() {
+        return this._playerController == null && (this._playerController = new XPlayerController(this)),
+        this._playerController
     }
     get mainScene() {
         return this.scene
@@ -233,91 +218,107 @@ export default class XSceneManager {
     get initEngineScaleNumber() {
         return this._initEngineScaleNumber
     }
-    setImageQuality(e) {
-        e == 0 ? (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.8),
-        logger.info("[Engine] change image quality to low, [" + this._initEngineScaleNumber * 1.8 + "]")) : e == 1 ? (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.5),
-        logger.info("[Engine] change image quality to mid, [" + this._initEngineScaleNumber * 1.5 + "]")) : e == 2 && (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1),
-        logger.info("[Engine] change image quality to high, [" + this._initEngineScaleNumber * 1 + "]"))
-    }
-    setNonlinearCanvasResize(e) {
-        this._nonlinearCanvasResize = e,
-        this._bChangeEngineSize = e,
-        e || this.engine.resize()
-    }
-    setBackgroundColor(e) {
-        this.scene.clearColor = new Color4(e.r,e.g,e.b,e.a)
-    }
-    setBackgroundImg(e) {
-        return this._backgroundImg != null && this._backgroundImg.url == e ? Promise.resolve(!0) : new Promise((t,r)=>{
-            this.urlTransformer(e).then(n=>{
+    setImageQuality(o) {
+        o == 0 ? (this.engine.setHardwareScalingLevel(this.adaptRatio(0)),
+        this.enablePostProcessing(!1),
+        this._lightManager.enableShadow(!1),
+        this._materialManager._updatePureVideoShaderInput(),
+        logger.info("[Engine] change image quality to low")) : o == 1 ? (this.engine.setHardwareScalingLevel(this.adaptRatio(1)),
+        this.enablePostProcessing(!0),
+        this._lightManager.enableShadow(!0),
+        this._materialManager._updatePureVideoShaderInput(),
+        logger.info("[Engine] change image quality to mid")) : o == 2 && (this.engine.setHardwareScalingLevel(this.adaptRatio(2)),
+        this.enablePostProcessing(!0),
+        this._lightManager.enableShadow(!0),
+        this._materialManager._updatePureVideoShaderInput(),
+        logger.info("[Engine] change image quality to high"))
+    }
+    adaptRatio(o) {
+        const s = Math.max(this.canvas.clientWidth, this.canvas.clientHeight);
+        return o == 0 ? s / 853 : o == 1 ? s / 1280 : s / 1920
+    }
+    setNonlinearCanvasResize(o) {
+        this._nonlinearCanvasResize = o,
+        this._bChangeEngineSize = o,
+        o || this.engine.resize()
+    }
+    changeCameraFovWithShaderUpdate(o) {
+        this.materialComponent.changeCameraFovWithShaderUpdate(o)
+    }
+    setBackgroundColor(o) {
+        this.scene.clearColor = new BABYLON.Color4(o.r,o.g,o.b,o.a)
+    }
+    setBackgroundImg(o) {
+        return this._backgroundImg != null && this._backgroundImg.url == o ? Promise.resolve(!0) : new Promise((s,c)=>{
+            this.urlTransformer(o).then(_=>{
                 this._backgroundImg == null ? this._backgroundImg = {
-                    layer: new Layer("tex_background_" + Date.now(),n,this.Scene,!0),
-                    url: e
-                } : this._backgroundImg.url != e && this._backgroundImg.layer != null && this._backgroundImg.layer.texture != null && (this._backgroundImg.layer.texture.updateURL(n),
+                    layer: new Layer("tex_background_" + Date.now(),_,this.Scene,!0),
+                    url: o
+                } : this._backgroundImg.url != o && this._backgroundImg.layer != null && this._backgroundImg.layer.texture != null && (this._backgroundImg.layer.texture.updateURL(_),
                 this._backgroundImg.layer.name = "tex_background_" + Date.now(),
-                this._backgroundImg.url = e),
-                t(!0)
+                this._backgroundImg.url = o),
+                s(!0)
             }
-            ).catch(n=>{
-                logger.error(`[Engine] set background image Error: ${n}`),
-                r(`[Engine] set background image Error: ${n}`)
+            ).catch(_=>{
+                logger.error(`[Engine] set background image Error: ${_}`),
+                c(`[Engine] set background image Error: ${_}`)
             }
             )
         }
         )
     }
     cleanTheWholeScene() {
-        const e = this.scene.getFrameId();
+        const o = this.scene.getFrameId();
         this.scene.onBeforeRenderObservable.clear(),
         this.scene.onAfterRenderObservable.clear(),
         this.scene.clearCachedVertexData(),
         this.scene.cleanCachedTextureBuffer(),
         this.scene.registerBeforeRender(()=>{
-            this.scene.getFrameId() - e > 5 && this.scene.dispose()
+            this.scene.getFrameId() - o > 5 && this.scene.dispose()
         }
         )
     }
-    getAreaAvatar(e, t) {
-        const r = [];
-        return this._avatarManager.getAvatarList().forEach(n=>{
-            const o = e
-              , a = n.position;
-            a && o && calcDistance3D(o, a) < t && r.push(n.id)
+    getAreaAvatar(o, s) {
+        const c = [];
+        return this._avatarManager.getAvatarList().forEach(_=>{
+            const b = o
+              , k = _.position;
+            k && b && calcDistance3D(b, k) < s && c.push(_.id)
         }
         ),
-        r
+        c
     }
-    setEngineSize(e) {
-        const t = e.width
-          , r = e.height
-          , n = this.canvas.width;
+    setEngineSize(o) {
+        const s = o.width
+          , c = o.height
+          , _ = this.canvas.width;
         this.canvas.height,
-        this.engine.setSize(Math.round(n), Math.round(n * (r / t)))
+        this.engine.setSize(Math.round(_), Math.round(_ * (c / s)))
     }
     getCurrentShaderMode() {
         return this._currentShader === this._materialManager.getDefaultShader() ? 0 : this._currentShader === this._materialManager.getPureVideoShader() ? 1 : 2
     }
-    addSkyTV(e, t) {
-        return this._skytv = new XTelevision(this.scene,e,this,t),
+    addSkyTV(o, s) {
+        return this._skytv = new XTelevision(this.scene,o,this,s),
         this._skytv
     }
-    addMv(e, t) {
-        this._mv.push(new XTelevision(this.scene,e,this,t))
+    addMv(o, s) {
+        this._mv.push(new XTelevision(this.scene,o,this,s))
     }
-    addMeshInfo(e) {
-        this._lowpolyManager.setMeshInfo(e)
+    addMeshInfo(o) {
+        this._lowpolyManager.setMeshInfo(o)
     }
     applyShader() {
-        return new Promise((e,t)=>{
+        return new Promise((o,s)=>{
             this.shaderMode == EShaderMode.videoAndPano || this.shaderMode == EShaderMode.video ? this.changeVideoShaderForLowModel() : this.shaderMode == EShaderMode.default && this.changeDefaultShaderForLowModel(),
-            e(!0)
+            o(!0)
         }
         )
     }
-    changeHardwareScaling(e) {
-        e < 1 ? e = 1 : e > 2.5 && (e = 2.5),
+    changeHardwareScaling(o) {
+        o < 1 ? o = 1 : o > 2.5 && (o = 2.5),
         this._bChangeEngineSize = !0,
-        this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * e)
+        this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * o)
     }
     getCurrentUsedPanoId() {
         return this._currentPanoId
@@ -325,70 +326,76 @@ export default class XSceneManager {
     render() {
         try {
             this.scene.render()
-        } catch (e) {
-            throw logger.error(`[Engine] Render Error: ${e}`),
-            e
+        } catch (o) {
+            throw logger.error(`[Engine] Render Error: ${o}`),
+            o
         }
     }
-    isReadyToRender(e) {
-        const {checkMesh: t=!0, checkEffect: r=!1, checkPostProgress: n=!1, checkParticle: o=!1, checkAnimation: a=!1, materialNameWhiteLists: s=[]} = e;
+    isReadyToRender(o) {
+        const {checkMesh: s=!0, checkEffect: c=!1, checkPostProgress: _=!1, checkParticle: b=!1, checkAnimation: k=!1, materialNameWhiteLists: j=[]} = o;
         if (this.scene._isDisposed)
             return logger.error("[Engine] this.scene._isDisposed== false "),
             !1;
-        let l;
-        const u = this.scene.getEngine();
-        if (r && !u.areAllEffectsReady())
+        let $;
+        const _e = this.scene.getEngine();
+        if (c && !_e.areAllEffectsReady())
             return logger.error("[Engine] engine.areAllEffectsReady == false"),
             !1;
-        if (a && this.scene._pendingData.length > 0)
+        if (k && this.scene._pendingData.length > 0)
             return logger.error("[Engine] scene._pendingData.length > 0 && animation error"),
             !1;
-        if (t) {
-            for (l = 0; l < this.scene.meshes.length; l++) {
-                const c = this.scene.meshes[l];
-                if (!c.isEnabled() || !c.subMeshes || c.subMeshes.length === 0 || c != null && c.material != null && !(c.material.name.startsWith("Pure") || c.material.name.startsWith("Pano")))
+        if (s) {
+            for ($ = 0; $ < this.scene.meshes.length; $++) {
+                const et = this.scene.meshes[$];
+                if (!et.isEnabled() || !et.subMeshes || et.subMeshes.length === 0 || et != null && et.material != null && !(et.material.name.startsWith("Pure") || et.material.name.startsWith("Pano")))
                     continue;
-                if (!c.isReady(!0))
-                    return logger.error(`[Engine] scene. mesh isReady == false, mesh name:${c.name}, mesh xtype: ${c == null ? void 0 : c.xtype}, mesh xgroup: ${c == null ? void 0 : c.xgroup}, mesh xskinInfo: ${c == null ? void 0 : c.xskinInfo}`),
+                if (!et.isReady(!0))
+                    return logger.error(`[Engine] scene. mesh isReady == false, mesh name:${et.name}, mesh xtype: ${et == null ? void 0 : et.xtype}, mesh xgroup: ${et == null ? void 0 : et.xgroup}, mesh xskinInfo: ${et == null ? void 0 : et.xskinInfo}`),
                     !1;
-                const h = c.hasThinInstances || c.getClassName() === "InstancedMesh" || c.getClassName() === "InstancedLinesMesh" || u.getCaps().instancedArrays && c.instances.length > 0;
-                for (const f of this.scene._isReadyForMeshStage)
-                    if (!f.action(c, h))
-                        return logger.error(`[Engine] scene._isReadyForMeshStage == false, mesh name:${c.name}, mesh xtype: ${c == null ? void 0 : c.xtype}, mesh xgroup: ${c == null ? void 0 : c.xgroup}, mesh xskinInfo: ${c == null ? void 0 : c.xskinInfo}`),
+                const tt = et.hasThinInstances || et.getClassName() === "InstancedMesh" || et.getClassName() === "InstancedLinesMesh" || _e.getCaps().instancedArrays && et.instances.length > 0;
+                for (const rt of this.scene._isReadyForMeshStage)
+                    if (!rt.action(et, tt))
+                        return logger.error(`[Engine] scene._isReadyForMeshStage == false, mesh name:${et.name}, mesh xtype: ${et == null ? void 0 : et.xtype}, mesh xgroup: ${et == null ? void 0 : et.xgroup}, mesh xskinInfo: ${et == null ? void 0 : et.xskinInfo}`),
                         !1
             }
-            for (l = 0; l < this.scene.geometries.length; l++)
-                if (this.scene.geometries[l].delayLoadState === 2)
-                    return logger.error("[Engine] geometry.delayLoadState === 2"),
+            for ($ = 0; $ < this.scene.geometries.length; $++) {
+                const et = this.scene.geometries[$];
+                if (et != null && et.delayLoadState === 2) {
+                    let tt = "";
+                    for (let rt = 0; rt < et.meshes.length; ++rt)
+                        tt = tt + et.meshes[rt].name + "(" + et.meshes[rt].xtype + ")+";
+                    return logger.error(`[Engine] geometry.delayLoadState === 2. ${tt}`),
                     !1
+                }
+            }
         }
-        if (n) {
+        if (_) {
             if (this.scene.activeCameras && this.scene.activeCameras.length > 0) {
-                for (const c of this.scene.activeCameras)
-                    if (!c.isReady(!0))
-                        return logger.error("[Engine] camera not ready === false, ", c.name),
+                for (const et of this.scene.activeCameras)
+                    if (!et.isReady(!0))
+                        return logger.error("[Engine] camera not ready === false, ", et.name),
                         !1
             } else if (this.scene.activeCamera && !this.scene.activeCamera.isReady(!0))
                 return logger.error("[Engine] activeCamera ready === false, ", this.scene.activeCamera.name),
                 !1
         }
-        if (o) {
-            for (const c of this.scene.particleSystems)
-                if (!c.isReady())
-                    return logger.error("[Engine] particleSystem ready === false, ", c.name),
+        if (b) {
+            for (const et of this.scene.particleSystems)
+                if (!et.isReady())
+                    return logger.error("[Engine] particleSystem ready === false, ", et.name),
                     !1
         }
         return !0
     }
-    changePanoShaderForLowModel(e) {
-        return logger.info(`[Engine] changePanoShaderForLowModel: ${e}`),
+    changePanoShaderForLowModel(o) {
+        return logger.info(`[Engine] changePanoShaderForLowModel: ${o}`),
         this._materialManager.allowYUVUpdate(),
-        new Promise((t,r)=>{
-            this._materialManager._isInDynamicRange(e) == !1 && r(!1),
-            this._currentPanoId = e,
-            this._currentShader = this._materialManager.getDynamicShader(e),
+        new Promise((s,c)=>{
+            this._materialManager._isInDynamicRange(o) == !1 && c(!1),
+            this._currentPanoId = o,
+            this._currentShader = this._materialManager.getDynamicShader(o),
             this.changeShaderForLowModel().then(()=>{
-                t(!0)
+                s(!0)
             }
             )
         }
@@ -407,45 +414,46 @@ export default class XSceneManager {
         this.changeShaderForLowModel()
     }
     changeShaderForLowModel() {
-        return new Promise((e,t)=>{
-            this._lowpolyManager.getMeshes().forEach(r=>{
-                r.setMaterial(this._currentShader)
+        return new Promise((o,s)=>{
+            this._lowpolyManager.getMeshes().forEach(c=>{
+                c.setMaterial(this._currentShader)
             }
             ),
             this._lowpolyManager.getCgMesh().mesh.material = this._currentShader,
-            e(!0)
+            o(!0)
         }
         )
     }
-    setIBL(e) {
-        this._lightManager.setIBL(e)
+    setIBL(o) {
+        this._lightManager.setIBL(o)
+    }
+    enablePostProcessing(o) {
+        this._pipeLine && (this._pipeLine.bloomEnabled = o)
     }
-    // 后处理bloom
     postprocessing() {
-        const e = new BABYLON.DefaultRenderingPipeline("default",!0,this.scene);
-        e.imageProcessingEnabled = !1,
-        // e.bloomEnabled = !0,
-        e.bloomThreshold = 1,
-        e.bloomWeight = 1,
-        e.bloomKernel = 64,
-        e.bloomScale = .1
-    }
-    // 查询name中包含SM_Stage和以ground开头的meshes
-    getGround() {
-        const t = this._lowpolyManager.getMeshes()
-          , r = [];
-        return t.forEach(n=>{
-            n.mesh.name.indexOf("SM_Stage") >= 0 && r.push(n.mesh)
-        }),
-        t.forEach(n=>{
-            n.mesh.name.indexOf("Level _L01") >= 0 && r.push(n.mesh)
-        }),
-        t.forEach(n=>{
-            n.mesh.name.indexOf("pSphere2") >= 0 && r.push(n.mesh)
-        }),
-        this.Scene.meshes.forEach(n=>{
-            n.name.split("_")[0] === "ground" && r.push(n)
-        }),
-        r
+        const o = new BABYLON.DefaultRenderingPipeline("default",!0,this.scene);
+        o.imageProcessingEnabled = !1,
+        o.bloomEnabled = !0,
+        o.bloomThreshold = 1.1,
+        o.bloomWeight = 1,
+        o.bloomKernel = 64,
+        o.bloomScale = .1,
+        this._pipeLine = o
+    }
+    getGround(o) {
+        const s = this._lowpolyManager.getMeshes()
+          , c = [];
+        return s.forEach(_=>{
+            _.mesh.name.indexOf("SM_Stage") >= 0 && c.push(_.mesh)
+        }
+        ),
+        this.Scene.meshes.forEach(_=>{
+            _.name.split("_")[0] === "ground" && c.push(_)
+        }
+        ),
+        c
+    }
+    setEnvLight(o) {
+        this.scene.environmentIntensity = o
     }
 }

+ 16 - 20
src/XSpriteManager.js

@@ -1,27 +1,23 @@
-let log$A = new Logger$1("subSequence")
-  , DEFAULT_FRAME_RATE = 30
-  , ROOT_MESH_ANIM_PROPERTY = ["scaling", "position", "rotation"]
-  , MESH_TAG = "XSubSequence";
-class XSpriteManager extends SpriteManager {
-    constructor(e, t, r, n, o) {
-        super(e, t, r, n, o);
-        E(this, "originalPositions");
+
+export default class XSpriteManager extends SpriteManager {
+    constructor(o, s, c, _, b) {
+        super(o, s, c, _, b),
         this.originalPositions = new Array,
-        this.sprites.forEach(a=>{
-            this.originalPositions.push(a.position)
+        this.sprites.forEach(k=>{
+            this.originalPositions.push(k.position)
         }
         )
     }
-    static Parse(e, t, r) {
-        const n = new XSpriteManager(e.name,"",e.capacity,{
-            width: e.cellWidth,
-            height: e.cellHeight
-        },t);
-        e.texture ? n.texture = BABYLON.Texture.Parse(e.texture, t, r) : e.textureName && (n.texture = new BABYLON.Texture(r + e.textureUrl,t,!0,e.invertY !== void 0 ? e.invertY : !0));
-        for (const o of e.sprites) {
-            const a = Sprite.Parse(o, n);
-            n.originalPositions.push(a.position)
+    static Parse(o, s, c) {
+        const _ = new XSpriteManager(o.name,"",o.capacity,{
+            width: o.cellWidth,
+            height: o.cellHeight
+        },s);
+        o.texture ? _.texture = BABYLON.Texture.Parse(o.texture, s, c) : o.textureName && (_.texture = new BABYLON.Texture(c + o.textureUrl,s,!0,o.invertY !== void 0 ? o.invertY : !0));
+        for (const b of o.sprites) {
+            const k = Sprite.Parse(b, _);
+            _.originalPositions.push(k.position)
         }
-        return n
+        return _
     }
 }

+ 114 - 106
src/XStaticMesh.js

@@ -1,97 +1,105 @@
 import EMeshType from "./enum/EMeshType.js"
 import Logger from "./Logger.js"
 
-const logger = new Logger('StaticMesh')
+const logger = new Logger('XStaticMesh')
 export default class XStaticMesh {
-    constructor({id: e, mesh: t, group: r="default", lod: n=0, xtype: o=EMeshType.XStaticMesh, skinInfo: a="default", url: s=""}) {
-        E(this, "_mesh");
-        E(this, "_id", "-1");
-        E(this, "_group");
-        E(this, "_lod");
-        E(this, "_isMoving", !1);
-        E(this, "_isRotating", !1);
-        E(this, "_isVisible", !0);
-        E(this, "_skinInfo");
-        this._id = e,
-        this._mesh = t,
-        this._group = r,
-        this._lod = n,
-        this._skinInfo = a,
+    constructor({id: o, mesh: s, group: c="default", lod: _=0, xtype: b=EMeshType.XStaticMesh, skinInfo: k="default", url: j=""}) {
+        this._mesh = void 0,
+        this._id = "-1",
+        this._isMoving = !1,
+        this._isRotating = !1,
+        this._isVisible = !0,
+        this.setVisibility = ($,_e)=>{
+            Array.isArray($) ? $.forEach(et=>{
+                this.setVisibility(et, _e)
+            }
+            ) : $.isAnInstance || ($.visibility = _e)
+        }
+        ,
+        this.setPickable = ($,_e)=>{
+            Array.isArray($) ? $.forEach(et=>{
+                this.setPickable(et, _e)
+            }
+            ) : ("isPickable"in $ && ($.isPickable = _e),
+            $.setEnabled(_e))
+        }
+        ,
+        this.hide = ()=>{
+            var $;
+            this._isVisible = !1,
+            this.mesh && this.setVisibility(this.mesh, 0),
+            this.mesh && this.setPickable(this.mesh, !1),
+            ($ = this.mesh) == null || $.getChildMeshes().forEach(_e=>{
+                this.setVisibility(_e, 0),
+                this.setPickable(_e, !1)
+            }
+            )
+        }
+        ,
+        this.show = ()=>{
+            var $;
+            this._isVisible = !0,
+            this.mesh && this.setVisibility(this.mesh, 1),
+            this.mesh && this.setPickable(this.mesh, !0),
+            ($ = this.mesh) == null || $.getChildMeshes().forEach(_e=>{
+                this.setVisibility(_e, 1),
+                this.setPickable(_e, !0)
+            }
+            )
+        }
+        ,
+        this.attachToAvatar = ($,_e={
+            x: 0,
+            y: .5,
+            z: 0
+        },et={
+            yaw: 0,
+            pitch: 0,
+            roll: 0
+        },tt={
+            x: .35,
+            y: .35,
+            z: .35
+        })=>{
+            const rt = ue4Scaling2Xverse(tt)
+              , it = ue4Rotation2Xverse(et)
+              , nt = ue4Position2Xverse(_e)
+              , at = this._mesh;
+            $ && at ? ($.setParent(at),
+            $.position = nt,
+            $.rotation = it,
+            $.scaling = rt) : logger.error("[Engine] avatar or attachment not found!")
+        }
+        ,
+        this.detachFromAvatar = ($,_e=!1)=>{
+            this._mesh && $ ? this._mesh.removeChild($) : logger.error("[Engine] avatar not found!")
+        }
+        ,
+        this._id = o,
+        this._mesh = s,
+        this._group = c,
+        this._lod = _,
+        this._skinInfo = k,
         this.unallowMove(),
-        this._mesh.xtype = o,
-        this._mesh.xid = e,
+        this._mesh.xtype = b,
+        this._mesh.xid = o,
         this._mesh.xgroup = this._group,
         this._mesh.xlod = this._lod,
         this._mesh.xskinInfo = this._skinInfo,
-        this._mesh.xurl = s
-    }
-    
-    setVisibility(e,t) {
-        Array.isArray(e) ? e.forEach(r=>{
-            this.setVisibility(r, t)
-        }
-        ) : e.isAnInstance || (e.visibility = t)
+        this._mesh.xurl = j
     }
-    
-    setPickable(e,t) {
-        Array.isArray(e) ? e.forEach(r=>{
-            this.setPickable(r, t)
-        }
-        ) : ("isPickable"in e && (e.isPickable = t),
-        e.setEnabled(t))
-    }
-    
-    hide() {
-        var e;
-        this._isVisible = !1,
-        this.mesh && this.setVisibility(this.mesh, 0),
-        this.mesh && this.setPickable(this.mesh, !1),
-        (e = this.mesh) == null || e.getChildMeshes().forEach(t=>{
-            this.setVisibility(t, 0),
-            this.setPickable(t, !1)
-        }
-        )
-    }
-    
-    show() {
-        var e;
-        this._isVisible = !0,
-        this.mesh && this.setVisibility(this.mesh, 1),
-        this.mesh && this.setPickable(this.mesh, !0),
-        (e = this.mesh) == null || e.getChildMeshes().forEach(t=>{
-            this.setVisibility(t, 1),
-            this.setPickable(t, !0)
-        }
-        )
-    }
-    
-    attachToAvatar(e, t={x:0, y:.5, z:0}, r={yaw:0, pitch:0, roll:0}, n={x:.35, y:.35, z:.35}) {
-        const o = ue4Scaling2Xverse(n)
-          , a = ue4Rotation2Xverse(r)
-          , s = ue4Position2Xverse(t)
-          , l = this._mesh;
-        e && l ? (e.setParent(l),
-        e.position = s,
-        e.rotation = a,
-        e.scaling = o) : logger.error("[Engine] avatar or attachment not found!")
-    }
-    
-    detachFromAvatar(e,t=!1) {
-        this._mesh && e ? this._mesh.removeChild(e) : logger.error("[Engine] avatar not found!")
-    }
-    
     get mesh() {
         return this._mesh
     }
     get position() {
-        var o;
+        var b;
         if (!this._mesh)
             return null;
-        const {x: e, y: t, z: r} = (o = this._mesh) == null ? void 0 : o.position;
+        const {x: o, y: s, z: c} = (b = this._mesh) == null ? void 0 : b.position;
         return xversePosition2Ue4({
-            x: e,
-            y: t,
-            z: r
+            x: o,
+            y: s,
+            z: c
         })
     }
     get id() {
@@ -113,15 +121,15 @@ export default class XStaticMesh {
         return this._skinInfo
     }
     allowMove() {
-        this._mesh != null && (this._mesh.getChildMeshes().forEach(e=>{
-            e.unfreezeWorldMatrix()
+        this._mesh != null && (this._mesh.getChildMeshes().forEach(o=>{
+            o.unfreezeWorldMatrix()
         }
         ),
         this._mesh.unfreezeWorldMatrix())
     }
     unallowMove() {
-        this._mesh != null && (this._mesh.getChildMeshes().forEach(e=>{
-            e.freezeWorldMatrix()
+        this._mesh != null && (this._mesh.getChildMeshes().forEach(o=>{
+            o.freezeWorldMatrix()
         }
         ),
         this._mesh.freezeWorldMatrix())
@@ -129,45 +137,45 @@ export default class XStaticMesh {
     getID() {
         return this._id
     }
-    setPosition(e) {
+    setPosition(o) {
         if (this._mesh) {
-            const t = ue4Position2Xverse(e);
-            this._mesh.position = t
+            const s = ue4Position2Xverse(o);
+            this._mesh.position = s
         } else
             logger.error("[Engine] no root for positioning")
     }
-    setRotation(e) {
-        const t = ue4Rotation2Xverse_mesh(e);
-        this._mesh ? this._mesh.rotation = t : logger.error("[Engine] no root for rotating")
+    setRotation(o) {
+        const s = ue4Rotation2Xverse_mesh(o);
+        this._mesh ? this._mesh.rotation = s : logger.error("[Engine] no root for rotating")
     }
-    setScale(e) {
-        this._mesh ? this._mesh.scaling = new BABYLON.Vector3(e,e,-e) : logger.error("[Engine] no root for scaling")
+    setScale(o) {
+        this._mesh ? this._mesh.scaling = new BABYLON.Vector3(o,o,-o) : logger.error("[Engine] no root for scaling")
     }
     disableAvatar() {
-        var e;
-        (e = this._mesh) == null || e.setEnabled(!1)
+        var o;
+        (o = this._mesh) == null || o.setEnabled(!1)
     }
     enableAvatar() {
-        var e;
-        (e = this._mesh) == null || e.setEnabled(!0)
+        var o;
+        (o = this._mesh) == null || o.setEnabled(!0)
     }
-    togglePickable(e) {
-        var t;
-        (t = this.mesh) == null || t.getChildMeshes().forEach(r=>{
-            "instances"in r && "isPickable"in r && (r.isPickable = e)
+    togglePickable(o) {
+        var s;
+        (s = this.mesh) == null || s.getChildMeshes().forEach(c=>{
+            "instances"in c && "isPickable"in c && (c.isPickable = o)
         }
         ),
-        this.mesh != null && "isPickable"in this.mesh && (this.mesh.isPickable = e)
+        this.mesh != null && "isPickable"in this.mesh && (this.mesh.isPickable = o)
     }
-    setMaterial(e) {
-        var t;
-        (t = this.mesh) == null || t.getChildMeshes().forEach(r=>{
-            "instances"in r && "material"in r && (r.material = e)
+    setMaterial(o) {
+        var s;
+        (s = this.mesh) == null || s.getChildMeshes().forEach(c=>{
+            "instances"in c && "material"in c && (c.material = o)
         }
         ),
-        this.mesh != null && "material"in this.mesh && (this.mesh.material = e)
+        this.mesh != null && "material"in this.mesh && (this.mesh.material = o)
     }
-    dispose(e=!1, t=!1) {
-        !this.mesh.isDisposed() && this.mesh.dispose(e, t)
+    dispose(o=!1, s=!1) {
+        !this.mesh.isDisposed() && this.mesh.dispose(o, s)
     }
 }

+ 414 - 433
src/XStaticMeshComponent.js

@@ -5,13 +5,247 @@ import XLowpolyModelError from "./error/XLowpolyModelError.js"
 import Logger from "./Logger.js"
 import XLowpolyJsonError from "./Error/XLowpolyJsonError.js"
 
-const logger = new Logger('StaticMeshComponent')
+const logger = new Logger('XStaticMeshComponent')
 export default class XStaticMeshComponent{
-    constructor(scenemanager) {
-        this._CgPlane
-        this._orijson
-        this._notUsedRegionLists
-
+    constructor(d) {
+        this.reg_staticmesh_partupdate = ()=>{
+            if (!GEngine.engineOption.bDisableCloudRender && (this._allowRegionUpdate && (this.scene.getFrameId(),
+            this._meshUpdateFrame()),
+            this._allowRegionForceLod)) {
+                this.scene.getFrameId() % 2 == 0 && this.setOneRegionLod(this._meshInfoKeys[this._currentUpdateRegionCount % this._meshInfoKeys.length].toString(), this._forceLod);
+                let s = !0;
+                const c = Array.from(this._currentMeshUsedLod.keys());
+                if (c.length > 0) {
+                    for (let _ = 0; _ < c.length; ++_)
+                        this._currentMeshUsedLod.get(c[_]) != this._forceLod && (s = !1);
+                    s && (this._allowRegionForceLod = !1)
+                }
+            }
+        }
+        ,
+        this.setMeshInfo = (o,s="")=>{
+            this._abosoluteUrl != o && (this._abosoluteUrl.length > 0 && this.deleteLastRegionMesh(),
+            this._partMeshSkinInfo = s,
+            this._abosoluteUrl = o,
+            this._rootDir = this._abosoluteUrl.slice(0, -4) + "/",
+            this.parseJson(this._rootDir + "meshInfo.json").then(()=>{
+                this.startMeshUpdate()
+            }
+            ))
+        }
+        ,
+        this._meshUpdateFrame = ()=>{
+            {
+                let o = this._meshInfoKeys[this._currentUpdateRegionCount % this._meshInfoKeys.length];
+                const s = !0;
+                let c = 3;
+                if (this._scenemanager != null && this._scenemanager.cameraComponent != null) {
+                    const _ = this._getMainPlayerPosition();
+                    if (_ != null) {
+                        if (this._cameraInRegionId >= 0) {
+                            const k = this.getRegionIdWhichIncludeCamera(_);
+                            (this._cameraInRegionId != k || this.regionIdInCamera.length == 0) && (this._cameraInRegionId = k,
+                            this.regionIdInCamera = this._getNeighborId(this._cameraInRegionId.toString()),
+                            this.regionIdInCameraConst = this.regionIdInCamera.slice());
+                            let j = this.regionIdInCamera.pop();
+                            for (; j != null; )
+                                if (this._notUsedRegionLists.indexOf(j) >= 0)
+                                    j = this.regionIdInCamera.pop();
+                                else
+                                    break;
+                            j != null && (o = j.toString())
+                        } else
+                            this._cameraInRegionId = this.getRegionIdWhichIncludeCamera(_);
+                        if (this._currentMeshUsedLod.size == 0 || this._notUsedRegionLists.indexOf(parseInt(o)) >= 0) {
+                            o = this._cameraInRegionId.toString();
+                            const k = this._getNeighborId(o);
+                            for (; k.length == 0 && (o = this.getNearestRegionIdWithCamera(_).toString()),
+                            this._notUsedRegionLists.indexOf(parseInt(o)) >= 0; )
+                                o = k.pop().toString()
+                        }
+                        const b = this._meshInfoJson[this._cameraInRegionId.toString()].lod;
+                        c = 3,
+                        this._cameraInRegionId.toString() == o ? c = this._regionLodRule[0] : b[0].indexOf(parseInt(o)) >= 0 ? c = this._regionLodRule[1] : b[1].indexOf(parseInt(o)) >= 0 ? c = this._regionLodRule[2] : b[2].indexOf(parseInt(o)) >= 0 ? c = this._regionLodRule[3] : c = this._regionLodRule[4]
+                    }
+                }
+                this.setOneRegionLod(o, c, s),
+                this.updateRegionNotInLocalNeighbor(),
+                this.cleanRootNodes()
+            }
+        }
+        ,
+        this.updateRegionNotInLocalNeighbor = ()=>{
+            Array.from(this._currentMeshUsedLod.keys()).forEach(s=>{
+                this.regionIdInCameraConst.indexOf(parseInt(s)) < 0 && this.setOneRegionLod(s, -1)
+            }
+            )
+        }
+        ,
+        this.cleanRootNodes = ()=>{
+            if (this.scene.getFrameId() % 3 == 0) {
+                const o = [];
+                this.scene.rootNodes.forEach(s=>{
+                    (s.getClassName() == "TransformNode" && s.getChildren().length == 0 || s.getClassName() == "Mesh" && s.name == "__root__" && s.getChildren().length == 0) && o.push(s)
+                }
+                ),
+                o.forEach(s=>{
+                    s.dispose()
+                }
+                )
+            }
+        }
+        ,
+        this.setOneRegionLod = (o,s,c=!0)=>{
+            this._currentUpdateRegionCount++;
+            const _ = this._calHashCode(this._rootDir)
+              , b = "region_" + _ + "_" + o;
+            if (s < 0) {
+                this._currentMeshUsedLod.has(o) && (this._currentMeshUsedLod.delete(o),
+                this._currentPartGroup.delete(b),
+                this.deleteMeshesByCustomProperty("group", "region_" + _ + "_" + o));
+                return
+            }
+            const k = this._rootDir + o + "_lod" + s + "_xverse.glb"
+              , j = this._currentMeshUsedLod.get(o);
+            this._currentPartGroup.add(b),
+            j != null ? j != s && (this._currentMeshUsedLod.set(o, s),
+            this._scenemanager.addNewLowPolyMesh({
+                url: k,
+                group: "region_" + _ + "_" + o,
+                pick: !0,
+                lod: s,
+                skinInfo: this._partMeshSkinInfo
+            }, [{
+                group: "region_" + _ + "_" + o,
+                mode: 0
+            }])) : (this._currentMeshUsedLod.set(o, s),
+            this._scenemanager.addNewLowPolyMesh({
+                url: k,
+                group: "region_" + _ + "_" + o,
+                pick: !0,
+                lod: s,
+                skinInfo: this._partMeshSkinInfo
+            }))
+        }
+        ,
+        this.checkPointInView = ({x: o, y: s, z: c})=>{
+            const _ = ue4Position2Xverse({
+                x: o,
+                y: s,
+                z: c
+            });
+            if (!_)
+                return !1;
+            for (let b = 0; b < 6; b++)
+                if (this.scene.frustumPlanes[b].dotCoordinate(_) < 0)
+                    return !1;
+            return !0
+        }
+        ,
+        this.addNewLowPolyMesh = (o,s,c)=>{
+            if (!o.url.endsWith("glb") && !o.url.startsWith("blob:"))
+                return o.url.endsWith("zip") ? (this.setMeshInfo(o.url, o.skinInfo),
+                Promise.resolve(!0)) : (logger.error("[Engine] input model path is error! ", o.url),
+                Promise.reject(new XLowpolyModelError("[Engine] input model path is error! " + o.url)));
+            {
+                const _ = o.url;
+                return new Promise((b,k)=>this._scenemanager.urlTransformer(o.url).then(j=>{
+                    o.url = j;
+                    const $ = new XStaticMeshFromOneGltf(this.scene,o)
+                      , _e = Date.now();
+                    return new Promise((et,tt)=>{
+                        $.loadMesh(c, !0).then(rt=>{
+                            const it = Date.now();
+                            if (this._scenemanager.engineRunTimeStats.timeArray_loadStaticMesh.add(it - _e),
+                            rt == !0) {
+                                const nt = this.getLowModelType(o);
+                                let at = 0;
+                                if (this._lowModel_group.has(nt) && (at = this._lowModel_group.get(nt).length),
+                                c != null && this._scenemanager.currentShader != null && this._scenemanager.currentShader.name != c.name && $.setMaterial(this._scenemanager.currentShader),
+                                this._allowRegionUpdate == !1 && nt.startsWith("region_"))
+                                    $.dispose();
+                                else if (this._staticmeshes.push($),
+                                this.lowmodelGroupMapAddValue(nt, $),
+                                s != null && s.length > 0) {
+                                    const ot = [];
+                                    for (let st = 0; st < s.length; ++st)
+                                        ot.push(s[st].group),
+                                        this.updateLowModelGroup(s[st], nt, at)
+                                }
+                                this._scenemanager.engineRunTimeStats.timeArray_updateStaticMesh.add(Date.now() - it),
+                                et(!0)
+                            } else
+                                tt(new XLowpolyModelError("[Engine] after lowmodel error!"))
+                        }
+                        ).catch(rt=>{
+                            logger.error("[Engine] load Mesh [" + _ + "] error! " + rt),
+                            tt(new XLowpolyModelError(`[Engine] load Mesh [${_}] error! ${rt}`))
+                        }
+                        )
+                    }
+                    )
+                }
+                ).then(j=>{
+                    j == !0 ? (logger.info(`[Engine] load Mesh [${_}] successfully.`),
+                    b(!0)) : k(!1)
+                }
+                ).catch(j=>{
+                    logger.error("[Engine] addNewLowPolyMesh [" + _ + "] error! " + j),
+                    k(new XLowpolyModelError(`[Engine] addNewLowPolyMesh [${_}] error! ${j}`))
+                }
+                ))
+            }
+        }
+        ,
+        this.toggleLowModelVisibility = o=>{
+            const {vis: s, groupName: c="", skinInfo: _=""} = o;
+            this._meshVis = s,
+            this._meshVisTypeName = {
+                groupName: c,
+                skinInfo: _
+            },
+            this._doMeshVisChangeNumber = 0,
+            c == _XStaticMeshComponent.ALL_MESHES || this._currentPartGroup.has(c) == !0 || this._partMeshSkinInfo == _ ? s == !1 ? (this._visCheckDurationFrameNumber = 100,
+            this.stopMeshUpdate()) : (this._visCheckDurationFrameNumber = 1,
+            this.startMeshUpdate()) : this._visCheckDurationFrameNumber = 1
+        }
+        ,
+        this.reg_staticmesh_visibility = ()=>{
+            if (!GEngine.engineOption.bDisableCloudRender && this._doMeshVisChangeNumber >= 0)
+                if (this._doMeshVisChangeNumber < this._visCheckDurationFrameNumber)
+                    if (this._doMeshVisChangeNumber = this._doMeshVisChangeNumber + 1,
+                    this._meshVisTypeName.groupName == _XStaticMeshComponent.ALL_MESHES)
+                        this._lowModel_group.forEach((o,s)=>{
+                            for (let c = 0, _ = o.length; c < _; ++c)
+                                o[c].toggleVisibility(this._meshVis)
+                        }
+                        );
+                    else {
+                        if (this._lowModel_group.has(this._meshVisTypeName.groupName))
+                            for (let o = 0; o < this._lowModel_group.get(this._meshVisTypeName.groupName).length; ++o)
+                                this._lowModel_group.get(this._meshVisTypeName.groupName)[o].toggleVisibility(this._meshVis);
+                        if (this._meshVisTypeName.skinInfo != "")
+                            for (let o = 0; o < this._staticmeshes.length; ++o)
+                                this._staticmeshes[o].skinInfo == this._meshVisTypeName.skinInfo && this._staticmeshes[o].toggleVisibility(this._meshVis)
+                    }
+                else
+                    this._meshVis = !0,
+                    this._meshVisTypeName = {
+                        groupName: "",
+                        skinInfo: ""
+                    },
+                    this._doMeshVisChangeNumber = -1
+        }
+        ,
+        this._getMeshesByCustomProperty = (o,s)=>{
+            let c = [];
+            return this._staticmeshes.forEach(_=>{
+                _[o] != null && _[o] == s && (c = c.concat(_.meshes))
+            }
+            ),
+            c
+        }
+        ,
         this._lowModel_group = new Map,
         this._staticmeshes = [],
         this._meshInfoJson = null,
@@ -24,8 +258,8 @@ export default class XStaticMeshComponent{
         this._allowRegionForceLod = !1,
         this._currentMeshUsedLod = new Map,
         this._currentPartGroup = new Set,
-        this._scenemanager = scenemanager,
-        this.scene = scenemanager.Scene,
+        this._scenemanager = d,
+        this.scene = d.Scene,
         this.regionIdInCamera = [],
         this.regionIdInCameraConst = [],
         this._cameraInRegionId = -1,
@@ -41,268 +275,13 @@ export default class XStaticMeshComponent{
         this.initCgLowModel(),
         this._regionPartLoop()
     }
-
-    reg_staticmesh_partupdate() {
-        this._allowRegionUpdate && (
-            this.scene.getFrameId(),
-            this._meshUpdateFrame()
-        )
-        if (this._allowRegionForceLod) {
-            this.scene.getFrameId() % 2 == 0 && this.setOneRegionLod(this._meshInfoKeys[this._currentUpdateRegionCount % this._meshInfoKeys.length].toString(), this._forceLod);
-            let t = !0;
-            const r = Array.from(this._currentMeshUsedLod.keys());
-            if (r.length > 0) {
-                for (let n = 0; n < r.length; ++n)
-                    this._currentMeshUsedLod.get(r[n]) != this._forceLod && (t = !1);
-                t && (this._allowRegionForceLod = !1)
-            }
-        }
-    }
-
-    setMeshInfo(e,t="") {
-        this._abosoluteUrl != e && (
-            this._abosoluteUrl.length > 0 && this.deleteLastRegionMesh(),
-            this._partMeshSkinInfo = t,
-            this._abosoluteUrl = e,
-            this._rootDir = this._abosoluteUrl.slice(0, -4) + "/",
-            this.parseJson(this._rootDir + "meshInfo.json").then(()=>{
-                this.startMeshUpdate()
-            })
-        )
-    }
-
-    _meshUpdateFrame() {
-        {
-            let e = this._meshInfoKeys[this._currentUpdateRegionCount % this._meshInfoKeys.length];
-            const t = !0;
-            let r = 3;
-            if (this._scenemanager != null && this._scenemanager.cameraComponent != null) {
-                const n = this._getMainPlayerPosition();
-                if (n != null) {
-                    if (this._cameraInRegionId >= 0) {
-                        const a = this.getRegionIdWhichIncludeCamera(n);
-                        (this._cameraInRegionId != a || this.regionIdInCamera.length == 0) && (this._cameraInRegionId = a,
-                        this.regionIdInCamera = this._getNeighborId(this._cameraInRegionId.toString()),
-                        this.regionIdInCameraConst = this.regionIdInCamera.slice());
-                        let s = this.regionIdInCamera.pop();
-                        for (; s != null; )
-                            if (this._notUsedRegionLists.indexOf(s) >= 0)
-                                s = this.regionIdInCamera.pop();
-                            else
-                                break;
-                        s != null && (e = s.toString())
-                    } else
-                        this._cameraInRegionId = this.getRegionIdWhichIncludeCamera(n);
-                    if (this._currentMeshUsedLod.size == 0 || this._notUsedRegionLists.indexOf(parseInt(e)) >= 0) {
-                        e = this._cameraInRegionId.toString();
-                        const a = this._getNeighborId(e);
-                        for (; a.length == 0 && (e = this.getNearestRegionIdWithCamera(n).toString()),
-                        this._notUsedRegionLists.indexOf(parseInt(e)) >= 0; )
-                            e = a.pop().toString()
-                    }
-                    const o = this._meshInfoJson[this._cameraInRegionId.toString()].lod;
-                    r = 3,
-                    this._cameraInRegionId.toString() == e ? r = this._regionLodRule[0] : o[0].indexOf(parseInt(e)) >= 0 ? r = this._regionLodRule[1] : o[1].indexOf(parseInt(e)) >= 0 ? r = this._regionLodRule[2] : o[2].indexOf(parseInt(e)) >= 0 ? r = this._regionLodRule[3] : r = this._regionLodRule[4]
-                }
-            }
-            this.setOneRegionLod(e, r, t),
-            this.updateRegionNotInLocalNeighbor(),
-            this.cleanRootNodes()
-        }
-    }
-
-    updateRegionNotInLocalNeighbor() {
-        Array.from(this._currentMeshUsedLod.keys()).forEach(t=>{
-            this.regionIdInCameraConst.indexOf(parseInt(t)) < 0 && this.setOneRegionLod(t, -1)
-        }
-        )
-    }
-
-    cleanRootNodes() {
-        if (this.scene.getFrameId() % 3 == 0) {
-            const e = [];
-            this.scene.rootNodes.forEach(t=>{
-                (t.getClassName() == "TransformNode" && t.getChildren().length == 0 || t.getClassName() == "Mesh" && t.name == "__root__" && t.getChildren().length == 0) && e.push(t)
-            }
-            ),
-            e.forEach(t=>{
-                t.dispose()
-            }
-            )
-        }
-    }
-
-    setOneRegionLod(e,t,r=!0) {
-        this._currentUpdateRegionCount++;
-        const n = this._calHashCode(this._rootDir)
-          , o = "region_" + n + "_" + e;
-        if (t < 0) {
-            this._currentMeshUsedLod.has(e) && (this._currentMeshUsedLod.delete(e),
-            this._currentPartGroup.delete(o),
-            this.deleteMeshesByCustomProperty("group", "region_" + n + "_" + e));
-            return
-        }
-        const a = this._rootDir + e + "_lod" + t + "_xverse.glb"
-          , s = this._currentMeshUsedLod.get(e);
-        this._currentPartGroup.add(o),
-        s != null ? s != t && (this._currentMeshUsedLod.set(e, t),
-        this._scenemanager.addNewLowPolyMesh({
-            url: a,
-            group: "region_" + n + "_" + e,
-            pick: !0,
-            lod: t,
-            skinInfo: this._partMeshSkinInfo
-        }, [{
-            group: "region_" + n + "_" + e,
-            mode: 0
-        }])) : (this._currentMeshUsedLod.set(e, t),
-        this._scenemanager.addNewLowPolyMesh({
-            url: a,
-            group: "region_" + n + "_" + e,
-            pick: !0,
-            lod: t,
-            skinInfo: this._partMeshSkinInfo
-        }))
-    }
-
-    checkPointInView({x: e, y: t, z: r}) {
-        const n = ue4Position2Xverse({
-            x: e,
-            y: t,
-            z: r
-        });
-        if (!n)
-            return !1;
-        for (let o = 0; o < 6; o++)
-            if (this.scene.frustumPlanes[o].dotCoordinate(n) < 0)
-                return !1;
-        return !0
-    }
-    
-    // 加载房间的glb模型
-    addNewLowPolyMesh(modelInfo, t, pureVideoShader) {
-
-        if (!modelInfo.url.endsWith("glb") && !modelInfo.url.startsWith("blob:")) {
-            return modelInfo.url.endsWith("zip") ? (
-                this.setMeshInfo(modelInfo.url, modelInfo.skinInfo),
-                Promise.resolve(!0)
-            ) : (
-                logger.error("[Engine] input model path is error! ", modelInfo.url),
-                Promise.reject(new XLowpolyModelError("[Engine] input model path is error! " + modelInfo.url))
-            );
-        }
-
-        const fileUrl = modelInfo.url;
-        return new Promise((o, a) => {
-            this._scenemanager.urlTransformer(modelInfo.url).then(blobUrl=>{
-                modelInfo.url = blobUrl;
-                const l = new XStaticMeshFromOneGltf(this.scene, modelInfo)
-                    , time0 = Date.now();
-
-                return new Promise((c, h)=>{
-                    l.loadMesh(pureVideoShader, !0).then(f => {
-                        const time1 = Date.now();
-                        this._scenemanager.engineRunTimeStats.timeArray_loadStaticMesh.add(time1 - time0)
-                        if (f == !0) {
-                            const modelType = this.getLowModelType(modelInfo);
-                            let g = 0;
-                            this._lowModel_group.has(modelType) && (g = this._lowModel_group.get(modelType).length)
-
-                            pureVideoShader && this._scenemanager.currentShader 
-                            && this._scenemanager.currentShader.name != pureVideoShader.name 
-                            && l.setMaterial(this._scenemanager.currentShader)
-
-                            if (this._allowRegionUpdate == !1 && modelType.startsWith("region_"))
-                                l.dispose();
-                            else if (
-                                this._staticmeshes.push(l),
-                                this.lowmodelGroupMapAddValue(modelType, l),
-                                t && t.length > 0
-                            ) {
-                                const m = [];
-                                for (let v = 0; v < t.length; ++v)
-                                    m.push(t[v].group),
-                                    this.updateLowModelGroup(t[v], modelType, g)
-                            }
-                            this._scenemanager.engineRunTimeStats.timeArray_updateStaticMesh.add(Date.now() - time1),
-                            c(!0)
-                        } else
-                            h(new XLowpolyModelError("[Engine] after lowmodel error!"))
-                    }
-                    ).catch(e=>{
-                        logger.error("[Engine] load Mesh [" + fileUrl + "] error! " + e),
-                        h(new XLowpolyModelError(`[Engine] load Mesh [${fileUrl}] error! ${e}`))
-                    })
-                })
-            }).then(s=>{
-                s == !0 ? (
-                    logger.info(`[Engine] load Mesh [${fileUrl}] successfully.`),
-                    o(!0)
-                ) : a(!1)
-            }
-            ).catch(s=>{
-                logger.error("[Engine] addNewLowPolyMesh [" + fileUrl + "] error! " + s),
-                a(new XLowpolyModelError(`[Engine] addNewLowPolyMesh [${fileUrl}] error! ${s}`))
-            })
-        })
-    }
-
-    toggleLowModelVisibility(e) {
-        const {vis: t, groupName: r="", skinInfo: n=""} = e;
-        this._meshVis = t,
-        this._meshVisTypeName = {
-            groupName: r,
-            skinInfo: n
-        },
-        this._doMeshVisChangeNumber = 0,
-        r == Te.ALL_MESHES || this._currentPartGroup.has(r) == !0 || this._partMeshSkinInfo == n ? t == !1 ? (this._visCheckDurationFrameNumber = 100,
-        this.stopMeshUpdate()) : (this._visCheckDurationFrameNumber = 1,
-        this.startMeshUpdate()) : this._visCheckDurationFrameNumber = 1
-    }
-    
-    reg_staticmesh_visibility() {
-        if (this._doMeshVisChangeNumber >= 0)
-            if (this._doMeshVisChangeNumber < this._visCheckDurationFrameNumber)
-                if (this._doMeshVisChangeNumber = this._doMeshVisChangeNumber + 1,
-                this._meshVisTypeName.groupName == Te.ALL_MESHES)
-                    this._lowModel_group.forEach((e,t)=>{
-                        for (let r = 0, n = e.length; r < n; ++r)
-                            e[r].toggleVisibility(this._meshVis)
-                    }
-                    );
-                else {
-                    if (this._lowModel_group.has(this._meshVisTypeName.groupName))
-                        for (let e = 0; e < this._lowModel_group.get(this._meshVisTypeName.groupName).length; ++e)
-                            this._lowModel_group.get(this._meshVisTypeName.groupName)[e].toggleVisibility(this._meshVis);
-                    if (this._meshVisTypeName.skinInfo != "")
-                        for (let e = 0; e < this._staticmeshes.length; ++e)
-                            this._staticmeshes[e].skinInfo == this._meshVisTypeName.skinInfo && this._staticmeshes[e].toggleVisibility(this._meshVis)
-                }
-            else
-                this._meshVis = !0,
-                this._meshVisTypeName = {
-                    groupName: "",
-                    skinInfo: ""
-                },
-                this._doMeshVisChangeNumber = -1
-    }
-
-    _getMeshesByCustomProperty(e,t) {
-        let r = [];
-        return this._staticmeshes.forEach(n=>{
-            n[e] != null && n[e] == t && (r = r.concat(n.meshes))
-        }
-        ),
-        r
-    }
-
     get cameraInRegionId() {
         return this._cameraInRegionId
     }
-    setRegionLodRule(e) {
-        return e.length != 5 ? !1 : (e.forEach(t=>{}
+    setRegionLodRule(d) {
+        return d.length != 5 ? !1 : (d.forEach(o=>{}
         ),
-        this._regionLodRule = e,
+        this._regionLodRule = d,
         !0)
     }
     get lowModel_group() {
@@ -312,84 +291,84 @@ export default class XStaticMeshComponent{
         this.scene.registerBeforeRender(this.reg_staticmesh_partupdate),
         this.scene.registerAfterRender(this.reg_staticmesh_visibility)
     }
-    _globalSearchCameraInWhichRegion(e, t) {
-        let r = -1;
-        for (let n = 0; n < t.length; ++n) {
-            const o = this._meshInfoJson[t[n].toString()].boundingbox
-              , a = o[0]
-              , s = o[1];
-            if (e.x >= a[0] && e.x <= s[0] && e.y >= a[1] && e.y <= s[1] && e.z >= a[2] && e.z <= s[2] || e.x >= s[0] && e.x <= a[0] && e.y >= s[1] && e.y <= a[1] && e.z >= s[2] && e.z <= a[2]) {
-                r = parseInt(t[n].toString());
+    _globalSearchCameraInWhichRegion(d, o) {
+        let s = -1;
+        for (let c = 0; c < o.length; ++c) {
+            const _ = this._meshInfoJson[o[c].toString()].boundingbox
+              , b = _[0]
+              , k = _[1];
+            if (d.x >= b[0] && d.x <= k[0] && d.y >= b[1] && d.y <= k[1] && d.z >= b[2] && d.z <= k[2] || d.x >= k[0] && d.x <= b[0] && d.y >= k[1] && d.y <= b[1] && d.z >= k[2] && d.z <= b[2]) {
+                s = parseInt(o[c].toString());
                 break
             }
         }
-        return r
+        return s
     }
-    getRegionIdByPosition(e) {
-        return this.getRegionIdWhichIncludeCamera(e)
+    getRegionIdByPosition(d) {
+        return this.getRegionIdWhichIncludeCamera(d)
     }
-    getRegionIdWhichIncludeCamera(e) {
-        let t = -1;
+    getRegionIdWhichIncludeCamera(d) {
+        let o = -1;
         if (this._allowRegionUpdate == !1)
-            return t;
-        if (this._cameraInRegionId == -1 ? t = this._globalSearchCameraInWhichRegion(e, this._meshInfoKeys) : (t = this._globalSearchCameraInWhichRegion(e, this.regionIdInCameraConst),
-        t == -1 && (t = this._globalSearchCameraInWhichRegion(e, this._meshInfoKeys))),
-        t == -1) {
-            let r = 1e7;
-            for (let n = 0; n < this._meshInfoKeys.length; ++n) {
-                const o = this._meshInfoJson[this._meshInfoKeys[n]].center
-                  , a = Math.abs(e.x - o[0]) + Math.abs(e.y - o[1]);
-                r > a && (r = a,
-                t = parseInt(this._meshInfoKeys[n]))
+            return o;
+        if (this._cameraInRegionId == -1 ? o = this._globalSearchCameraInWhichRegion(d, this._meshInfoKeys) : (o = this._globalSearchCameraInWhichRegion(d, this.regionIdInCameraConst),
+        o == -1 && (o = this._globalSearchCameraInWhichRegion(d, this._meshInfoKeys))),
+        o == -1) {
+            let s = 1e7;
+            for (let c = 0; c < this._meshInfoKeys.length; ++c) {
+                const _ = this._meshInfoJson[this._meshInfoKeys[c]].center
+                  , b = Math.abs(d.x - _[0]) + Math.abs(d.y - _[1]);
+                s > b && (s = b,
+                o = parseInt(this._meshInfoKeys[c]))
             }
         }
-        return t
+        return o
     }
-    getNearestRegionIdWithCamera(e) {
-        let t = 1
-          , r = 1e7;
-        for (let n = 0; n < this._meshInfoKeys.length; ++n) {
-            if (this._notUsedRegionLists.indexOf(parseInt(this._meshInfoKeys[n])) >= 0)
+    getNearestRegionIdWithCamera(d) {
+        let o = 1
+          , s = 1e7;
+        for (let c = 0; c < this._meshInfoKeys.length; ++c) {
+            if (this._notUsedRegionLists.indexOf(parseInt(this._meshInfoKeys[c])) >= 0)
                 continue;
-            const o = this._meshInfoJson[this._meshInfoKeys[n]].center
-              , a = Math.abs(e.x - o[0]) + Math.abs(e.y - o[1]);
-            r > a && (r = a,
-            t = parseInt(this._meshInfoKeys[n]))
+            const _ = this._meshInfoJson[this._meshInfoKeys[c]].center
+              , b = Math.abs(d.x - _[0]) + Math.abs(d.y - _[1]);
+            s > b && (s = b,
+            o = parseInt(this._meshInfoKeys[c]))
         }
-        return t
+        return o
     }
-    _getNeighborId(e) {
-        const t = this._meshInfoJson[e].lod;
-        let r = [];
-        const n = Object.keys(t);
-        for (let o = n.length - 1; o >= 0; --o)
-            r = r.concat(t[n[o]]);
-        return r.push(parseInt(e)),
-        r
+    _getNeighborId(d) {
+        const o = this._meshInfoJson[d].lod;
+        let s = [];
+        const c = Object.keys(o);
+        for (let _ = c.length - 1; _ >= 0; --_)
+            s = s.concat(o[c[_]]);
+        return s.push(parseInt(d)),
+        s
     }
     _getMainPlayerPosition() {
-        const e = this._scenemanager.cameraComponent.getCameraPose().position
-          , t = this._scenemanager.avatarComponent.getMainAvatar();
-        if (t != null && t != null) {
-            const r = t.position;
-            if (r != null)
-                return r
+        const d = this._scenemanager.cameraComponent.getCameraPose().position
+          , o = this._scenemanager.avatarComponent.getMainAvatar();
+        if (o != null && o != null) {
+            const s = o.position;
+            if (s != null)
+                return s
         }
-        return e
+        return d
     }
-    _calHashCode(e) {
-        return hashCode(e) + "_" + this._partMeshSkinInfo
+    _calHashCode(d) {
+        return hashCode(d) + "_" + this._partMeshSkinInfo
     }
-    forceAllRegionLod(e=3) {
-        e < 0 && (e = 0),
-        e > 3 && (e = 3),
+    forceAllRegionLod(d=3) {
+        d < 0 && (d = 0),
+        d > 3 && (d = 3),
         this.stopMeshUpdate(),
         this._allowRegionForceLod = !0,
-        this._forceLod = e
+        this._forceLod = d
     }
     deleteLastRegionMesh() {
         if (this._rootDir != "") {
-            const e = this._calHashCode(this._rootDir);
+            const d = this._calHashCode(this._rootDir);
             this._currentMeshUsedLod.clear(),
             this._currentPartGroup.clear(),
             this._meshInfoJson = null,
@@ -400,7 +379,7 @@ export default class XStaticMeshComponent{
             this._partMeshSkinInfo = "",
             this._abosoluteUrl = "",
             this.stopMeshUpdate(),
-            this.deleteMeshesByCustomProperty("group", "region_" + e, !0)
+            this.deleteMeshesByCustomProperty("group", "region_" + d, !0)
         }
     }
     startMeshUpdate() {
@@ -409,170 +388,172 @@ export default class XStaticMeshComponent{
     stopMeshUpdate() {
         this._allowRegionUpdate = !1
     }
-    parseJson(e) {
-        return new Promise((t,r)=>this._scenemanager.urlTransformer(e).then(n=>{
-            const o = new XMLHttpRequest;
-            o.open("get", n),
-            o.send(null),
-            o.onload = ()=>{
-                if (o.status == 200) {
-                    const a = JSON.parse(o.responseText);
-                    this._orijson = a,
+    parseJson(d) {
+        return new Promise((o,s)=>this._scenemanager.urlTransformer(d).then(c=>{
+            const _ = new XMLHttpRequest;
+            _.open("get", c),
+            _.send(null),
+            _.onload = ()=>{
+                if (_.status == 200) {
+                    const b = JSON.parse(_.responseText);
+                    this._orijson = b,
                     this._meshInfoJson = this._orijson.usedRegion,
                     this._notUsedRegionLists = this._orijson.notUsedRegion,
                     this._meshInfoKeys = Object.keys(this._meshInfoJson),
                     logger.info("[Engine] parse zip mesh info successful"),
-                    t()
+                    o()
                 }
             }
             ,
-            o.onerror = ()=>{
-                logger.error(`[Engine] load zip mesh info json error, (provided by blob): ${n}`),
-                r(new XLowpolyJsonError(`[Engine] load zip mesh info json error, (provided by blob): ${n}`))
+            _.onerror = ()=>{
+                logger.error(`[Engine] load zip mesh info json error, (provided by blob): ${c}`),
+                s(new XLowpolyJsonError(`[Engine] load zip mesh info json error, (provided by blob): ${c}`))
             }
         }
-        ).catch(n=>{
-            logger.error(`[Engine] load zip mesh info json error: ${n}, link:${e}`),
-            r(new XLowpolyJsonError(`[Engine] load zip mesh info json error: ${n}, link: ${e}`))
+        ).catch(c=>{
+            logger.error(`[Engine] load zip mesh info json error: ${c}, link:${d}`),
+            s(new XLowpolyJsonError(`[Engine] load zip mesh info json error: ${c}, link: ${d}`))
         }
         ))
     }
     initCgLowModel() {
-        const e = BABYLON.MeshBuilder.CreatePlane("CgPlane", {
+        const d = BABYLON.MeshBuilder.CreatePlane("CgPlane", {
             size: 400
         });
-        e.position = new BABYLON.Vector3(0,1010,0),
-        e.rotation = new BABYLON.Vector3(3 * Math.PI / 2,0,0),
+        d.position = new BABYLON.Vector3(0,1010,0),
+        d.rotation = new BABYLON.Vector3(3 * Math.PI / 2,0,0),
         this._CgPlane = new XStaticMesh({
             id: "CgPlane",
-            mesh: e,
+            mesh: d,
             xtype: EMeshType.Cgplane
         }),
         this._CgPlane.hide()
     }
-    getLowModelType(e) {
-        let t = "";
-        return e.group != null ? t = e.group : t = "default",
-        t
-    }
-    lowmodelGroupMapAddValue(e, t) {
-        const r = this._lowModel_group.get(e);
-        r != null ? (r.push(t),
-        this._lowModel_group.set(e, r)) : this._lowModel_group.set(e, [t])
-    }
-    updateLowModelGroup(e, t, r) {
-        let n = r;
-        e.group == t || (n = -1),
-        e.mode == 0 ? this.deleteLowModelGroup(e.group, n) : e.mode == 1 ? this.toggleVisibleLowModelGroup(!1, e.group, n) : e.mode == 2 && this.toggleVisibleLowModelGroup(!0, e.group, n)
-    }
-    toggleVisibleLowModelGroup(e, t, r=-1) {
-        if (this._lowModel_group.has(t)) {
-            const n = this._lowModel_group.get(t);
-            let o = n.length;
-            r >= 0 && o >= r && (o = r);
-            for (let a = 0; a < o; ++a)
-                n[a].toggleVisibility(e)
+    getLowModelType(d) {
+        let o = "";
+        return d.group != null ? o = d.group : o = "default",
+        o
+    }
+    lowmodelGroupMapAddValue(d, o) {
+        const s = this._lowModel_group.get(d);
+        s != null ? (s.push(o),
+        this._lowModel_group.set(d, s)) : this._lowModel_group.set(d, [o])
+    }
+    updateLowModelGroup(d, o, s) {
+        let c = s;
+        d.group == o || (c = -1),
+        d.mode == 0 ? this.deleteLowModelGroup(d.group, c) : d.mode == 1 ? this.toggleVisibleLowModelGroup(!1, d.group, c) : d.mode == 2 && this.toggleVisibleLowModelGroup(!0, d.group, c)
+    }
+    toggleVisibleLowModelGroup(d, o, s=-1) {
+        if (this._lowModel_group.has(o)) {
+            const c = this._lowModel_group.get(o);
+            let _ = c.length;
+            s >= 0 && _ >= s && (_ = s);
+            for (let b = 0; b < _; ++b)
+                c[b].toggleVisibility(d)
         }
     }
-    deleteLowModelGroup(e, t=-1) {
-        if (this._lowModel_group.has(e)) {
-            const o = this._lowModel_group.get(e);
-            let a = o.length;
-            t >= 0 && a >= t && (a = t);
-            for (let s = 0; s < a; ++s)
-                o[s].dispose();
-            t >= 0 ? this._lowModel_group.set(e, this._lowModel_group.get(e).slice(a)) : this._lowModel_group.delete(e)
+    deleteLowModelGroup(d, o=-1) {
+        if (this._lowModel_group.has(d)) {
+            const _ = this._lowModel_group.get(d);
+            let b = _.length;
+            o >= 0 && b >= o && (b = o);
+            for (let k = 0; k < b; ++k)
+                _[k].dispose();
+            o >= 0 ? this._lowModel_group.set(d, this._lowModel_group.get(d).slice(b)) : this._lowModel_group.delete(d)
         }
-        const r = this._lowModel_group.get(e)
-          , n = [];
-        r != null && r.length > 0 ? this._staticmeshes.forEach(o=>{
-            if (o.group != e)
-                n.push(o);
+        const s = this._lowModel_group.get(d)
+          , c = [];
+        s != null && s.length > 0 ? this._staticmeshes.forEach(_=>{
+            if (_.group != d)
+                c.push(_);
             else
-                for (let a = 0; a < r.length; ++a)
-                    o.groupUuid == r[a].groupUuid && n.push(o)
+                for (let b = 0; b < s.length; ++b)
+                    _.groupUuid == s[b].groupUuid && c.push(_)
         }
-        ) : this._staticmeshes.forEach(o=>{
-            o.group != e && n.push(o)
+        ) : this._staticmeshes.forEach(_=>{
+            _.group != d && c.push(_)
         }
         ),
-        this._staticmeshes = n
+        this._staticmeshes = c
     }
-    deleteMeshesByGroup(e) {
-        this.deleteLowModelGroup(e)
+    deleteMeshesByGroup(d) {
+        this.deleteLowModelGroup(d)
     }
-    deleteMeshesById(e) {
-        this.deleteMeshesByCustomProperty("id", e)
+    deleteMeshesById(d) {
+        this.deleteMeshesByCustomProperty("id", d)
     }
-    deleteMeshesByLoD(e) {
-        this.deleteMeshesByCustomProperty("lod", e)
+    deleteMeshesByLoD(d) {
+        this.deleteMeshesByCustomProperty("lod", d)
     }
-    deleteMeshesBySkinInfo(e) {
-        this.deleteMeshesByCustomProperty("skinInfo", e)
+    deleteMeshesBySkinInfo(d) {
+        this.deleteMeshesByCustomProperty("skinInfo", d)
     }
-    removeMeshesFromSceneByGroup(e) {
-        this.removeMeshesFromSceneByCustomProperty("group", e)
+    removeMeshesFromSceneByGroup(d) {
+        this.removeMeshesFromSceneByCustomProperty("group", d)
     }
-    removeMeshesFromSceneById(e) {
-        this.removeMeshesFromSceneByCustomProperty("id", e)
+    removeMeshesFromSceneById(d) {
+        this.removeMeshesFromSceneByCustomProperty("id", d)
     }
-    addMeshesToSceneByGroup(e) {
-        this.addMeshesToSceneByCustomProperty("group", e)
+    addMeshesToSceneByGroup(d) {
+        this.addMeshesToSceneByCustomProperty("group", d)
     }
-    addMeshesToSceneById(e) {
-        this.addMeshesToSceneByCustomProperty("id", e)
+    addMeshesToSceneById(d) {
+        this.addMeshesToSceneByCustomProperty("id", d)
     }
-    removeMeshesFromSceneByCustomProperty(e, t, r=!1) {
-        this._staticmeshes.forEach(n=>{
-            n.isinscene && n[e] != null && (r ? n[e].indexOf(t) < 0 || n.removeFromScene() : n[e] != t || n.removeFromScene())
+    removeMeshesFromSceneByCustomProperty(d, o, s=!1) {
+        this._staticmeshes.forEach(c=>{
+            c.isinscene && c[d] != null && (s ? c[d].indexOf(o) < 0 || c.removeFromScene() : c[d] != o || c.removeFromScene())
         }
         )
     }
-    addMeshesToSceneByCustomProperty(e, t, r=!1) {
-        this._staticmeshes.forEach(n=>{
-            n.isinscene == !1 && n[e] != null && (r ? n[e].indexOf(t) < 0 || n.addToScene() : n[e] != t || n.addToScene())
+    addMeshesToSceneByCustomProperty(d, o, s=!1) {
+        this._staticmeshes.forEach(c=>{
+            c.isinscene == !1 && c[d] != null && (s ? c[d].indexOf(o) < 0 || c.addToScene() : c[d] != o || c.addToScene())
         }
         )
     }
-    deleteMeshesByCustomProperty(e, t, r=!1) {
-        const n = [];
-        this._staticmeshes.forEach(a=>{
-            a[e] != null && (r ? a[e].indexOf(t) < 0 ? n.push(a) : a.dispose() : a[e] != t ? n.push(a) : a.dispose())
+    deleteMeshesByCustomProperty(d, o, s=!1) {
+        const c = [];
+        this._staticmeshes.forEach(b=>{
+            b[d] != null && (s ? b[d].indexOf(o) < 0 ? c.push(b) : b.dispose() : b[d] != o ? c.push(b) : b.dispose())
         }
         ),
-        this._staticmeshes = n;
-        const o = Array.from(this._lowModel_group.keys());
-        for (let a = 0; a < o.length; ++a) {
-            const s = o[a]
-              , l = this._lowModel_group.get(s);
-            if (l != null) {
-                const u = [];
-                for (let c = 0; c < l.length; ++c)
-                    l[c][e] != null && (r ? l[c][e].indexOf(t) < 0 && u.push(l[c]) : l[c][e] != t && u.push(l[c]));
-                u.length > 0 ? this._lowModel_group.set(s, u) : this._lowModel_group.delete(s)
+        this._staticmeshes = c;
+        const _ = Array.from(this._lowModel_group.keys());
+        for (let b = 0; b < _.length; ++b) {
+            const k = _[b]
+              , j = this._lowModel_group.get(k);
+            if (j != null) {
+                const $ = [];
+                for (let _e = 0; _e < j.length; ++_e)
+                    j[_e][d] != null && (s ? j[_e][d].indexOf(o) < 0 && $.push(j[_e]) : j[_e][d] != o && $.push(j[_e]));
+                $.length > 0 ? this._lowModel_group.set(k, $) : this._lowModel_group.delete(k)
             }
         }
     }
     getMeshes() {
-        let e = [];
-        for (let t = 0; t < this._staticmeshes.length; ++t)
-            e = e.concat(this._staticmeshes[t].meshes);
-        return e
+        let d = [];
+        for (let o = 0; o < this._staticmeshes.length; ++o)
+            d = d.concat(this._staticmeshes[o].meshes);
+        return d
     }
     getCgMesh() {
         return this._CgPlane
     }
-    getMeshesByGroup(e="default") {
-        const t = this._lowModel_group.get(e);
-        if (t != null) {
-            let r = [];
-            for (let n = 0; n < t.length; ++n)
-                r = r.concat(t[n].meshes);
-            return r
+    getMeshesByGroup(d="default") {
+        const o = this._lowModel_group.get(d);
+        if (o != null) {
+            let s = [];
+            for (let c = 0; c < o.length; ++c)
+                s = s.concat(o[c].meshes);
+            return s
         } else
             return null
     }
-    getMeshesByGroup2(e="default") {
-        return this._getMeshesByCustomProperty("group", e)
+    getMeshesByGroup2(d="default") {
+        return this._getMeshesByCustomProperty("group", d)
     }
-}
+}
+
+XStaticMeshComponent.ALL_MESHES = "ALL_MESHES";

+ 73 - 80
src/XStaticMeshFromOneGltf.js

@@ -4,74 +4,67 @@ import util from "./util.js"
 import EMeshType from "./enum/EMeshType.js"
 import Logger from "./Logger.js"
 
-const logger = new Logger('StaticMeshComponent')
+const logger = new Logger('XStaticMeshFromOneGltf')
 export default class XStaticMeshFromOneGltf {
-    
-    constructor(scene, options) {
-
-        this._meshes = [],
-        this._scene = scene,
-        this._url = options.url,
-
-        options.group != null ? this._group = options.group : this._group = "default",
-        options.pick != null ? this._pickable = options.pick : this._pickable = !1,
-        options.id != null ? this._id = options.id : this._id = "default",
-        options.lod != null ? this._lod = options.lod : this._lod = -1,
-        options.skinInfo != null ? this._skinInfo = options.skinInfo : this._skinInfo = "default",
-
-        this._groupUuid = util.uuid(),
-        this._isInScene = !1
-    }
-    
-    loadMesh(pureVideoShader, t) {
-        const meshLength0 = this._meshes.length
-          , isVisi = t ? 1 : 0
-          , url = this._url;
-
-        return BABYLON.SceneLoader.LoadAssetContainerAsync("", url, this._scene, ()=>{
-            this._scene.blockMaterialDirtyMechanism = !0
-        }, ".glb").then(modelInfo => {
-
-            for (let s = modelInfo.materials.length - 1; s >= 0; --s)
-                modelInfo.materials[s].dispose();
-
-            this._scene.blockMaterialDirtyMechanism = !0;
-
-            for (let i = 0; i < modelInfo.meshes.length; ++i) {
-                const mesh = modelInfo.meshes[i];
-                if ("instances"in mesh) {
-                    "visibility"in mesh && (mesh.visibility = 0);
-                    "isPickable"in mesh && (mesh.isPickable = this._pickable);
-                    pureVideoShader && (mesh.material = pureVideoShader);
-                    "hasVertexAlpha"in mesh && (mesh.hasVertexAlpha = !1);
-
-                    const xMesh = new XStaticMesh({
-                        id: this._groupUuid + "-" + Math.random().toString(36).substr(2, 5),
-                        mesh,
-                        lod: this._lod,
-                        group: this._group,
-                        url: this._url,
-                        xtype: EMeshType.XStaticMesh,
-                        skinInfo: this._skinInfo
-                    });
-                    // 房间模型初始180度矫正
-                    xMesh.setRotation({pitch: 0, roll:0, yaw:180})
-                    this._meshes.push(xMesh);
+    constructor(o, s) {
+        this.loadMesh = (c,_)=>{
+            const b = this._meshes.length;
+            GEngine.engineOption.bDisableCloudRender && (_ = !1);
+            const k = _ ? 1 : 0
+              , j = this._url;
+            return BABYLON.SceneLoader.LoadAssetContainerAsync("", j, this._scene, ()=>{
+                this._scene.blockMaterialDirtyMechanism = !0
+            }
+            , ".glb").then($=>{
+                for (let _e = $.materials.length - 1; _e >= 0; --_e)
+                    $.materials[_e].dispose();
+                this._scene.blockMaterialDirtyMechanism = !0;
+                for (let _e = 0; _e < $.meshes.length; ++_e) {
+                    const et = $.meshes[_e];
+                    if ("instances"in et) {
+                        "visibility"in et && (et.visibility = 0),
+                        "isPickable"in et && (et.isPickable = this._pickable),
+                        c != null && (et.material = c),
+                        "hasVertexAlpha"in et && (et.hasVertexAlpha = !1);
+                        const tt = new XStaticMesh({
+                            id: this._groupUuid + "-" + Math.random().toString(36).substr(2, 5),
+                            mesh: et,
+                            lod: this._lod,
+                            group: this._group,
+                            url: this._url,
+                            xtype: EMeshType.XStaticMesh,
+                            skinInfo: this._skinInfo
+                        });
+                        this._meshes.push(tt)
+                    }
+                    this._scene.addMesh(et)
                 }
-                this._scene.addMesh(mesh);
+                return !0
             }
-            return !0
-        }).then(() => {
-            this._isInScene = !0;
-            for (let i = meshLength0; i < this._meshes.length; ++i)
-                this._meshes[i].mesh.visibility = isVisi;
-            return Promise.resolve(!0)
-        }).catch(e => {
-            logger.error("[Engine] input gltf mesh uri error! " + e),
-            Promise.reject(new XLowpolyModelError("[Engine] input gltf mesh uri error! " + e))
-        })
+            ).then(()=>{
+                this._isInScene = !0;
+                for (let $ = b; $ < this._meshes.length; ++$)
+                    this._meshes[$].mesh.visibility = k;
+                return Promise.resolve(!0)
+            }
+            ).catch($=>{
+                logger.error("[Engine] input gltf mesh uri error! " + $),
+                Promise.reject(new XLowpolyModelError("[Engine] input gltf mesh uri error! " + $))
+            }
+            )
+        }
+        ,
+        this._meshes = [],
+        this._scene = o,
+        this._url = s.url,
+        s.group != null ? this._group = s.group : this._group = "default",
+        s.pick != null ? this._pickable = s.pick : this._pickable = !1,
+        s.id != null ? this._id = s.id : this._id = "default",
+        s.lod != null ? this._lod = s.lod : this._lod = -1,
+        s.skinInfo != null ? this._skinInfo = s.skinInfo : this._skinInfo = "default",
+        this._groupUuid = uuid$2(),
+        this._isInScene = !1
     }
-
     get isinscene() {
         return this._isInScene
     }
@@ -99,32 +92,32 @@ export default class XStaticMeshFromOneGltf {
     removeFromScene() {
         if (this._isInScene) {
             this._isInScene = !1;
-            for (let e = 0, t = this._meshes.length; e < t; ++e)
-                this._meshes[e].mesh != null && this._scene.removeMesh(this._meshes[e].mesh)
+            for (let o = 0, s = this._meshes.length; o < s; ++o)
+                this._meshes[o].mesh != null && this._scene.removeMesh(this._meshes[o].mesh)
         }
     }
     addToScene() {
         if (this._isInScene == !1) {
             this._isInScene = !0;
-            for (let e = 0, t = this._meshes.length; e < t; ++e)
-                this._meshes[e].mesh != null && this._scene.addMesh(this._meshes[e].mesh)
+            for (let o = 0, s = this._meshes.length; o < s; ++o)
+                this._meshes[o].mesh != null && this._scene.addMesh(this._meshes[o].mesh)
         }
     }
-    toggleVisibility(e) {
-        const t = e ? 1 : 0;
-        for (let r = 0, n = this._meshes.length; r < n; ++r)
-            "visibility"in this._meshes[r].mesh && (this._meshes[r].mesh.visibility = t)
+    toggleVisibility(o) {
+        const s = o ? 1 : 0;
+        for (let c = 0, _ = this._meshes.length; c < _; ++c)
+            "visibility"in this._meshes[c].mesh && (this._meshes[c].mesh.visibility = s)
     }
-    togglePickable(e) {
-        for (let t = 0, r = this._meshes.length; t < r; ++t)
-            "isPickable"in this._meshes[t].mesh && (this._meshes[t].mesh.isPickable = e)
+    togglePickable(o) {
+        for (let s = 0, c = this._meshes.length; s < c; ++s)
+            "isPickable"in this._meshes[s].mesh && (this._meshes[s].mesh.isPickable = o)
     }
-    setMaterial(e) {
-        for (let t = 0, r = this._meshes.length; t < r; ++t)
-            "material"in this._meshes[t].mesh && (this._meshes[t].mesh.material = e)
+    setMaterial(o) {
+        for (let s = 0, c = this._meshes.length; s < c; ++s)
+            "material"in this._meshes[s].mesh && (this._meshes[s].mesh.material = o)
     }
     dispose() {
-        for (let e = 0, t = this._meshes.length; e < t; ++e)
-            this._meshes[e].mesh.dispose(!1, !1)
+        for (let o = 0, s = this._meshes.length; o < s; ++o)
+            this._meshes[o].mesh.dispose(!1, !1)
     }
 }

+ 34 - 42
src/XStats.js

@@ -1,34 +1,26 @@
 export default class XStats {
-    constructor(e) {
-        E(this, "scene");
-        E(this, "sceneInstrumentation");
-        E(this, "engineInstrumentation");
-        E(this, "caps");
-        E(this, "engine");
-        E(this, "_canvas");
-        E(this, "_osversion");
-        E(this, "_scenemanager");
-        this._scenemanager = e,
-        this.scene = e.Scene,
-        this._canvas = e.canvas,
+    constructor(o) {
+        this._scenemanager = o,
+        this.scene = o.Scene,
+        this._canvas = o.canvas,
         this.initSceneInstrument()
     }
     initSceneInstrument() {
-        this.sceneInstrumentation = new BABYLON.SceneInstrumentation(this.scene);
-        this.sceneInstrumentation.captureCameraRenderTime = !0;
-        this.sceneInstrumentation.captureActiveMeshesEvaluationTime = !0;
-        this.sceneInstrumentation.captureRenderTargetsRenderTime = !0;
-        this.sceneInstrumentation.captureFrameTime = !0;
-        this.sceneInstrumentation.captureRenderTime = !0;
-        this.sceneInstrumentation.captureInterFrameTime = !0;
-        this.sceneInstrumentation.captureParticlesRenderTime = !0;
-        this.sceneInstrumentation.captureSpritesRenderTime = !0;
-        this.sceneInstrumentation.capturePhysicsTime = !0;
-        this.sceneInstrumentation.captureAnimationsTime = !0;
-        this.engineInstrumentation = new BABYLON.EngineInstrumentation(this.scene.getEngine());
-        this.caps = this.scene.getEngine().getCaps();
-        this.engine = this.scene.getEngine();
-        this._osversion = this.osVersion();
+        this.sceneInstrumentation = new BABYLON.SceneInstrumentation(this.scene),
+        this.sceneInstrumentation.captureCameraRenderTime = !0,
+        this.sceneInstrumentation.captureActiveMeshesEvaluationTime = !0,
+        this.sceneInstrumentation.captureRenderTargetsRenderTime = !0,
+        this.sceneInstrumentation.captureFrameTime = !0,
+        this.sceneInstrumentation.captureRenderTime = !0,
+        this.sceneInstrumentation.captureInterFrameTime = !0,
+        this.sceneInstrumentation.captureParticlesRenderTime = !0,
+        this.sceneInstrumentation.captureSpritesRenderTime = !0,
+        this.sceneInstrumentation.capturePhysicsTime = !0,
+        this.sceneInstrumentation.captureAnimationsTime = !0,
+        this.engineInstrumentation = new BABYLON.EngineInstrumentation(this.scene.getEngine()),
+        this.caps = this.scene.getEngine().getCaps(),
+        this.engine = this.scene.getEngine(),
+        this._osversion = this.osVersion()
     }
     getFrameTimeCounter() {
         return this.sceneInstrumentation.frameTimeCounter.current
@@ -82,10 +74,10 @@ export default class XStats {
         return this.scene.rootNodes.length
     }
     getRenderTargetRenderTime() {
-        const e = this.getDrawCallTime()
-          , t = this.getActiveMeshEvaluationTime()
-          , r = this.getCameraRenderTime() - (t + e);
-        return this.getRTT1Time() + r
+        const o = this.getDrawCallTime()
+          , s = this.getActiveMeshEvaluationTime()
+          , c = this.getCameraRenderTime() - (s + o);
+        return this.getRTT1Time() + c
     }
     getRegisterBeforeRenderTime() {
         return this.sceneInstrumentation.registerBeforeTimeCounter.current
@@ -103,12 +95,12 @@ export default class XStats {
         return this.scene.onAfterRenderObservable.observers.length
     }
     getTotalMeshByType() {
-        const e = new Map;
-        return this.scene.meshes.forEach(t=>{
-            e.has(t.xtype) ? e.set(t.xtype, e.get(t.xtype) + 1) : e.set(t.xtype, 1)
+        const o = new Map;
+        return this.scene.meshes.forEach(s=>{
+            o.has(s.xtype) ? o.set(s.xtype, o.get(s.xtype) + 1) : o.set(s.xtype, 1)
         }
         ),
-        e
+        o
     }
     getHardwareRenderInfo() {
         return {
@@ -175,14 +167,14 @@ export default class XStats {
         }
     }
     getFps() {
-        const e = this.sceneInstrumentation.frameTimeCounter.lastSecAverage
-          , t = this.sceneInstrumentation.interFrameTimeCounter.lastSecAverage;
-        return 1e3 / (e + t)
+        const o = this.sceneInstrumentation.frameTimeCounter.lastSecAverage
+          , s = this.sceneInstrumentation.interFrameTimeCounter.lastSecAverage;
+        return 1e3 / (o + s)
     }
     osVersion() {
-        const e = window.navigator.userAgent;
-        let t;
-        return /iphone|ipad|ipod/gi.test(e) ? t = e.match(/OS (\d+)_(\d+)_?(\d+)?/) : /android/gi.test(e) && (t = e.match(/Android (\d+)/)),
-        t != null && t.length > 0 ? t[0] : null
+        const o = window.navigator.userAgent;
+        let s;
+        return /iphone|ipad|ipod/gi.test(o) ? s = o.match(/OS (\d+)_(\d+)_?(\d+)?/) : /android/gi.test(o) && (s = o.match(/Android (\d+)/)),
+        s != null && s.length > 0 ? s[0] : null
     }
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 451 - 450
src/XSubSequence.js


+ 211 - 245
src/XTelevision.js

@@ -3,32 +3,22 @@ import EMeshType from "./enum/EMeshType.js"
 import Logger from "./Logger.js"
 import Stream from "./Stream.js";
 
-const logger = new Logger('Television')
+const logger = new Logger('XTelevision')
 export default class XTelevision {
-    constructor(scene, meshUrl, scenemanager, option) {
-        E(this, "videoElement");
-        E(this, "meshPath");
-        E(this, "scene");
-        E(this, "tvMeshs", []);
-        E(this, "vAng");
-        E(this, "videoMat");
-        E(this, "videoTexture");
-        E(this, "widthHeightScale");
-        E(this, "fitMode");
-        E(this, "_scenemanager");
-
-        this.scene = scene
-        this.meshPath = meshUrl
-        this._scenemanager = scenemanager
-        if (option != null) {
-            const {vAng=0, widthHeightScale=-1, fitMode="fill"} = option;
-            this.vAng = vAng,
-            this.widthHeightScale = widthHeightScale,
-            this.fitMode = fitMode
+    constructor(o, s, c, _) {
+        if (this.tvMeshs = [],
+        this.scene = o,
+        this.meshPath = s,
+        this._scenemanager = c,
+        _ != null) {
+            const {vAng: b=0, widthHeightScale: k=-1, fitMode: j="fill"} = _;
+            this.vAng = b,
+            this.widthHeightScale = k,
+            this.fitMode = j
         }
     }
-    set tvWidthHeightscale(e) {
-        this.widthHeightScale = e
+    set tvWidthHeightscale(o) {
+        this.widthHeightScale = o
     }
     get tvWidthHeightscale() {
         return this.widthHeightScale
@@ -36,67 +26,69 @@ export default class XTelevision {
     get tvFitMode() {
         return this.fitMode
     }
-    set tvFitMode(e) {
-        this.fitMode = e
+    set tvFitMode(o) {
+        this.fitMode = o
     }
-    setPlaySpeed(e) {
-        this.videoElement != null && (this.videoElement.playbackRate = e)
+    setPlaySpeed(o) {
+        this.videoElement != null && (this.videoElement.playbackRate = o)
     }
     getMesh() {
         return this.tvMeshs
     }
-    createElement(e, t=!1) {
-        const n = new Stream().el;
-        return n.loop = t,
-        n.autoplay = !0,
-        n.src = e,
-        n
+    createElement(o, s=!1) {
+        const _ = new Stream().el;
+        return _.loop = s,
+        _.autoplay = !0,
+        _.src = o,
+        _
     }
-    async setUrl(e) {
-        const {url, isLive: r=!1, poster: n=null, bLoop: o=!1, bMuted: a=!0} = e || {};
-
-        if (typeof url != "string")
-            return logger.error("[Engine] Tv setUrl Error, url must be string: ", url),
+    async setUrl(o) {
+        const {url: s, isLive: c=!1, poster: _=null, bLoop: b=!1, bMuted: k=!0} = o || {};
+        if (typeof s != "string")
+            return logger.error("[Engine] Tv setUrl Error, url must be string: ", s),
             Promise.reject(new XTvMediaUrlError("[Engine] url must be string"));
-
         if (this.videoElement) {
-            this.videoElement.src = url,
-            n != null && n.length > 0 && (this.videoElement.poster = n);
-            const l = this.play();
-            return "bMuted"in e && l !== void 0 && l.then(()=>{
-                this.videoElement.muted = a
-            }),
-            this.videoElement.addEventListener("loadedmetadata", u=>{
-                this.videoElement.videoWidth > 0 
-                ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight) 
-                : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
-            }),
+            this.videoElement.src = s,
+            _ != null && _.length > 0 && (this.videoElement.poster = _);
+            const $ = this.play();
+            return "bMuted"in o && $ !== void 0 && $.then(()=>{
+                this.videoElement.muted = k
+            }
+            ),
+            this.videoElement.addEventListener("loadedmetadata", _e=>{
+                this.videoElement.videoWidth > 0 ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight) : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
+            }
+            ),
             Promise.resolve(this)
         }
-
-        const s = this.createElement(url, o);
-        n != null && n.length > 0 && (s.poster = n)
-        return this.setVideo(s, r).then(()=>{
-            const l = this.videoElement && this.videoElement.play();
-            "bMuted"in e && l !== void 0 && l.then(()=>{
-                this.videoElement.muted = a
-            })
-        }).catch(l=>{
-            logger.error("[Engine] setUrl  error! " + l),
-            new XTvMediaUrlError("[Engine] setUrl  error! " + l)
-        })
+        const j = this.createElement(s, b);
+        return _ != null && _.length > 0 && (j.poster = _),
+        this.setVideo(j, c).then(()=>{
+            var _e;
+            const $ = (_e = this.videoElement) == null ? void 0 : _e.play();
+            "bMuted"in o && $ !== void 0 && $.then(()=>{
+                this.videoElement.muted = k
+            }
+            )
+        }
+        ).catch($=>{
+            const _e = new XTvMediaUrlError("[Engine] setUrl  error! " + $);
+            return logger.error(_e),
+            Promise.reject(_e)
+        }
+        )
     }
-    setCurrentTime(e) {
+    setCurrentTime(o) {
         if (!this.videoElement) {
             logger.warn("[Engine] The television is not been initialize succesfully");
             return
         }
-        const {currentTime: t} = e;
-        if (typeof t != "number") {
+        const {currentTime: s} = o;
+        if (typeof s != "number") {
             logger.warn("[Engine] video currentTime must be number");
             return
         }
-        this.videoElement.currentTime = t / 1e3
+        this.videoElement.currentTime = s / 1e3
     }
     getCurrentTime() {
         return this.videoElement ? this.videoElement.currentTime * 1e3 : -1
@@ -107,9 +99,9 @@ export default class XTelevision {
         this.videoElement ? this.videoElement.play() : Promise.resolve()
     }
     pause() {
-        var e;
+        var o;
         return logger.info("[Engine] Pause television"),
-        (e = this.videoElement) == null ? void 0 : e.pause()
+        (o = this.videoElement) == null ? void 0 : o.pause()
     }
     stop() {
         logger.info("[Engine] Stop television"),
@@ -122,10 +114,10 @@ export default class XTelevision {
         ),
         this.toggle(!1)
     }
-    toggle(e) {
-        logger.info(`[Engine] Set Tv visibility = ${e}`);
-        for (let t = 0; t < this.tvMeshs.length; ++t)
-            e == !0 ? this.tvMeshs[t].show() : this.tvMeshs[t].hide()
+    toggle(o) {
+        logger.info(`[Engine] Set Tv visibility = ${o}`);
+        for (let s = 0; s < this.tvMeshs.length; ++s)
+            o == !0 ? this.tvMeshs[s].show() : this.tvMeshs[s].hide()
     }
     getVideoMat() {
         return this.videoMat
@@ -137,211 +129,185 @@ export default class XTelevision {
         this.videoMat.setFloat("tvWidthHeightScale", this.widthHeightScale),
         this.videoMat.setFloat("bforceforceKeepContent", -1)) : this.videoMat.setFloat("tvWidthHeightScale", -1)
     }
-    async setVideo(e, t=!1, r=!0) 
-    {
-        return this.tvMeshs.length != 0 ? (
-            logger.warn(`[Engine] Set Video. length!=0, mesh: ${this.meshPath}, src: ${e.src}`),
-
-            new Promise((n,o)=>
-            {
-                if (!(e instanceof HTMLVideoElement))
-                    return logger.error("[Engine] Error, param of setVideo must be a HTMLVideoElement"),
-                    o(new XTvVideoElementError("[Engine] param of setVideo must be a HTMLVideoElement"));
-
-                this.videoElement = e,
-                
-                r == !1 
-                && (t == !1 || checkOS().isIOS) 
-                && e.crossOrigin !== "anonymous" 
-                && (e.crossOrigin = "anonymous", e.load()),
-
-                this.videoElement.addEventListener("loadedmetadata", a=>{
-                    this.videoElement.videoWidth > 0 ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight) : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
-                }),
-                this.videoTexture.updateURL(this.videoElement.src),
-
-                n(this)
-            })
-        ) : (
-            logger.warn(`[Engine] Set Video. length==0, mesh: ${this.meshPath}, src: ${e.src}`),
-
-            this.meshPath == "" 
-            ? (
-                logger.error("[Engine] Error, television meshPath is empty."),
-                Promise.reject(new XTvVideoElementError("[Engine] Error, television meshPath is empty."))
-            ) 
-            : this._scenemanager.urlTransformer(this.meshPath).then(n => new Promise((o,a) =>
-                e instanceof HTMLVideoElement 
-                ? (
-                    this.videoElement = e,
-
-                    r == !1 
-                    && (t == !1 || checkOS().isIOS) 
-                    && e.crossOrigin !== "anonymous"
-                    && (e.crossOrigin = "anonymous", e.load()),
-
-                    BABYLON.SceneLoader.LoadAssetContainerAsync("", n, this.scene, null, ".glb").then(s=>{
-                        for (let u = s.materials.length - 1; u >= 0; --u) s.materials[u].dispose();
-
-                        this.videoTexture = new BABYLON.VideoTexture("videoTex_" + Date.now(),e,this.scene,!1,!0,void 0,{
-                            autoPlay: !0,
-                            autoUpdateTexture: !0,
-                            muted: !0
-                        }),
-                        this.videoTexture.vAng = this.vAng,
-                        this.videoMat = new BABYLON.ShaderMaterial("videoMat_" + Date.now(),this.scene,{
-                            vertexSource: tvVertex,
-                            fragmentSource: tvFragment
-                        },{
-                            attributes: ["uv", "position"],
-                            uniforms: ["view", "projection", "worldViewProjection", "world"]
-                        }),
-                        this.videoMat.setTexture("texture_video", this.videoTexture),
-                        this.videoMat.setFloat("tvWidthHeightScale", -1),
-                        this.videoMat.setFloat("mvWidthHeightScale", 16 / 9),
-                        this.videoMat.setFloat("bforceforceKeepContent", -1),
-                        this.videoMat.backFaceCulling = !1,
-                        this.videoMat.sideOrientation = BABYLON.Mesh.FRONTSIDE,
-
-                        this.videoElement.addEventListener("loadedmetadata", u=>{
-                            this.videoElement.videoWidth > 0 
-                            ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight) 
-                            : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
-                        });
-
-                        const tvMeshs = [];
-                        for (let u = 0; u < s.meshes.length; ++u)
-                            s.meshes[u].visibility = 1,
-                            s.meshes[u].isPickable = !0,
-                            s.meshes[u].checkCollisions = !1,
-                            s.meshes[u].material = this.videoMat,
-                            "hasVertexAlpha"in s.meshes[u] && (s.meshes[u].hasVertexAlpha = !1),
-                            this.scene.addMesh(s.meshes[u]),
-                            tvMeshs.push(new XStaticMesh({
-                                id: s.meshes[u].id,
-                                mesh: s.meshes[u],
-                                xtype: EMeshType.Tv
-                            }));
-
-                        this.changeTvFitMode(),
-                        this.tvMeshs = tvMeshs,
-                        this.toggle(!0),
-                        o(this)
-                    }).catch(s=>{
-                        logger.error("[Engine] setVideo: create Tv by input mesh error! " + s),
-                        a(new XTvModelError("[Engine] setVideo: create Tv by input mesh error! " + s))
-                    })
-                )
-                : a(new XTvVideoElementError("[Engine] param of setVideo must be a HTMLVideoElement"))
-            ))
-        )
+    async setVideo(o, s=!1, c=!0) {
+        return this.tvMeshs.length != 0 ? (logger.warn(`[Engine] Set Video. length!=0, mesh: ${this.meshPath}, src: ${o.src}`),
+        new Promise((_,b)=>{
+            if (!(o instanceof HTMLVideoElement))
+                return logger.error("[Engine] Error, param of setVideo must be a HTMLVideoElement"),
+                b(new XTvVideoElementError("[Engine] param of setVideo must be a HTMLVideoElement"));
+            this.videoElement = o,
+            c == !1 && (s == !1 || checkOS().isIOS) && o.crossOrigin !== "anonymous" && (o.crossOrigin = "anonymous",
+            o.load()),
+            this.videoElement.addEventListener("loadedmetadata", k=>{
+                this.videoElement.videoWidth > 0 ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight) : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
+            }
+            ),
+            this.videoTexture.updateURL(this.videoElement.src),
+            _(this)
+        }
+        )) : (logger.warn(`[Engine] Set Video. length==0, mesh: ${this.meshPath}, src: ${o.src}`),
+        this.meshPath == "" ? (logger.error("[Engine] Error, television meshPath is empty."),
+        Promise.reject(new XTvVideoElementError("[Engine] Error, television meshPath is empty."))) : this._scenemanager.urlTransformer(this.meshPath).then(_=>new Promise((b,k)=>o instanceof HTMLVideoElement ? (this.videoElement = o,
+        c == !1 && (s == !1 || checkOS().isIOS) && o.crossOrigin !== "anonymous" && (o.crossOrigin = "anonymous",
+        o.load()),
+        BABYLON.SceneLoader.LoadAssetContainerAsync("", _, this.scene, null, ".glb").then(j=>{
+            for (let _e = j.materials.length - 1; _e >= 0; --_e)
+                j.materials[_e].dispose();
+            const $ = [];
+            this.videoTexture = new VideoTexture("videoTex_" + Date.now(),o,this.scene,!1,!0,void 0,{
+                autoPlay: !0,
+                autoUpdateTexture: !0,
+                muted: !0
+            }),
+            this.videoTexture.vAng = this.vAng,
+            this.videoMat = new BABYLON.ShaderMaterial("videoMat_" + Date.now(),this.scene,{
+                vertexSource: tvVertex,
+                fragmentSource: tvFragment
+            },{
+                attributes: ["uv", "position"],
+                uniforms: ["view", "projection", "worldViewProjection", "world"]
+            }),
+            this.videoMat.setTexture("texture_video", this.videoTexture),
+            this.videoMat.setFloat("tvWidthHeightScale", -1),
+            this.videoMat.setFloat("mvWidthHeightScale", 16 / 9),
+            this.videoMat.setFloat("bforceforceKeepContent", -1),
+            this.videoMat.backFaceCulling = !1,
+            this.videoMat.sideOrientation = BABYLON.Mesh.FRONTSIDE,
+            this.videoElement.addEventListener("loadedmetadata", _e=>{
+                this.videoElement.videoWidth > 0 ? this.videoMat.setFloat("mvWidthHeightScale", this.videoElement.videoWidth / this.videoElement.videoHeight) : this.videoMat.setFloat("mvWidthHeightScale", 16 / 9)
+            }
+            );
+            for (let _e = 0; _e < j.meshes.length; ++_e)
+                j.meshes[_e].visibility = 1,
+                j.meshes[_e].isPickable = !0,
+                j.meshes[_e].checkCollisions = !1,
+                j.meshes[_e].material = this.videoMat,
+                "hasVertexAlpha"in j.meshes[_e] && (j.meshes[_e].hasVertexAlpha = !1),
+                this.scene.addMesh(j.meshes[_e]),
+                $.push(new XStaticMesh({
+                    id: j.meshes[_e].id,
+                    mesh: j.meshes[_e],
+                    xtype: EMeshType.Tv
+                }));
+            this.changeTvFitMode(),
+            this.tvMeshs = $,
+            GEngine.engineOption.bDisableLocalRender ? this.toggle(!1) : this.toggle(!0),
+            b(this)
+        }
+        ).catch(j=>{
+            logger.error("[Engine] setVideo: create Tv by input mesh error! " + j),
+            k(new XTvModelError("[Engine] setVideo: create Tv by input mesh error! " + j))
+        }
+        )) : k(new XTvVideoElementError("[Engine] param of setVideo must be a HTMLVideoElement")))))
     }
-    async setSameVideo(e, t="") {
-        return e == null || e == null ? (logger.error("[Engine] setSameVideo: input material is null or undefined "),
-        Promise.reject(new XTvModelError("[Engine] setSameVideo input material is null or undefined !"))) : this.tvMeshs.length != 0 && t == "" ? (logger.warn(`[Engine] Set mirror video. length!=0, mesh: ${this.meshPath}`),
-        new Promise((r,n)=>{
+    async setSameVideo(o, s="") {
+        return o == null || o == null ? (logger.error("[Engine] setSameVideo: input material is null or undefined "),
+        Promise.reject(new XTvModelError("[Engine] setSameVideo input material is null or undefined !"))) : this.tvMeshs.length != 0 && s == "" ? (logger.warn(`[Engine] Set mirror video. length!=0, mesh: ${this.meshPath}`),
+        new Promise((c,_)=>{
             try {
-                this.videoMat = e,
-                this.tvMeshs.forEach(o=>{
-                    o.setMaterial(e)
+                this.videoMat = o,
+                this.tvMeshs.forEach(b=>{
+                    b.setMaterial(o)
                 }
                 ),
                 this.changeTvFitMode(),
-                r(this)
-            } catch (o) {
-                logger.error("[Engine] setSameVideo: create Tv by input mesh error! " + o),
-                n(new XTvModelError("[Engine] create Tv by input mesh error! " + o))
+                c(this)
+            } catch (b) {
+                logger.error("[Engine] setSameVideo: create Tv by input mesh error! " + b),
+                _(new XTvModelError("[Engine] create Tv by input mesh error! " + b))
             }
         }
-        )) : (t != "" && (this.meshPath = t,
+        )) : (s != "" && (this.meshPath = s,
         this.widthHeightScale = -1),
         this.meshPath == "" ? (logger.error("[Engine] Error, setSameVideo television meshPath is empty."),
         Promise.reject(new XTvVideoElementError("[Engine] Error, setSameVideo television meshPath is empty."))) : (logger.warn(`[Engine] Set mirror video. length==0, mesh: ${this.meshPath}`),
-        this._scenemanager.urlTransformer(this.meshPath).then(r=>new Promise((n,o)=>(this.videoMat = e,
-        e != null && e.getActiveTextures()[0] && (this.videoElement = e == null ? void 0 : e.getActiveTextures()[0].video),
-        BABYLON.SceneLoader.LoadAssetContainerAsync("", r, this.scene, null, ".glb").then(a=>{
-            for (let l = a.materials.length - 1; l >= 0; --l)
-                a.materials[l].dispose();
-            const s = [];
-            for (let l = 0; l < a.meshes.length; ++l)
-                a.meshes[l].visibility = 0,
-                a.meshes[l].isPickable = !0,
-                a.meshes[l].checkCollisions = !1,
-                a.meshes[l].material = this.videoMat,
-                "hasVertexAlpha"in a.meshes[l] && (a.meshes[l].hasVertexAlpha = !1),
-                this.scene.addMesh(a.meshes[l]),
-                s.push(new XStaticMesh({
-                    id: a.meshes[l].id,
-                    mesh: a.meshes[l],
+        this._scenemanager.urlTransformer(this.meshPath).then(c=>new Promise((_,b)=>(this.videoMat = o,
+        o != null && o.getActiveTextures()[0] && (this.videoElement = o == null ? void 0 : o.getActiveTextures()[0].video),
+        BABYLON.SceneLoader.LoadAssetContainerAsync("", c, this.scene, null, ".glb").then(k=>{
+            for (let $ = k.materials.length - 1; $ >= 0; --$)
+                k.materials[$].dispose();
+            const j = [];
+            for (let $ = 0; $ < k.meshes.length; ++$)
+                k.meshes[$].visibility = 0,
+                k.meshes[$].isPickable = !0,
+                k.meshes[$].checkCollisions = !1,
+                k.meshes[$].material = this.videoMat,
+                "hasVertexAlpha"in k.meshes[$] && (k.meshes[$].hasVertexAlpha = !1),
+                this.scene.addMesh(k.meshes[$]),
+                j.push(new XStaticMesh({
+                    id: k.meshes[$].id,
+                    mesh: k.meshes[$],
                     xtype: EMeshType.Tv
                 }));
-            t != "" && this.cleanTv(!1, !1),
-            this.tvMeshs = s,
+            s != "" && this.cleanTv(!1, !1),
+            this.tvMeshs = j,
             this.changeTvFitMode(),
-            n(this)
+            GEngine.engineOption.bDisableLocalRender && this.toggle(!1),
+            _(this)
         }
-        ).catch(a=>{
-            logger.error("[Engine] setSameVideo: create Tv by input mesh error! " + a),
-            o(new XTvModelError("[Engine] create Tv by input mesh error! " + a))
+        ).catch(k=>{
+            logger.error("[Engine] setSameVideo: create Tv by input mesh error! " + k),
+            b(new XTvModelError("[Engine] create Tv by input mesh error! " + k))
         }
         ))))))
     }
-    async changeTvModel(e="") {
-        return e != "" && (this.meshPath = e,
+    async changeTvModel(o="") {
+        return o != "" && (this.meshPath = o,
         this.widthHeightScale = -1),
         this.meshPath == "" ? (logger.error("[Engine] Error,changeTvModel television meshPath is empty."),
         Promise.reject(new XTvVideoElementError("[Engine] Error, changeTvModel television meshPath is empty."))) : this.videoMat == null || this.videoMat == null ? (logger.error("[Engine] changeTvModel: videoMat is null or undefined! "),
-        Promise.reject(new XTvModelError("[Engine] changeTvModel: videoMat is null or undefined!"))) : this._scenemanager.urlTransformer(this.meshPath).then(t=>new Promise((r,n)=>BABYLON.SceneLoader.LoadAssetContainerAsync("", t, this.scene, null, ".glb").then(o=>{
-            for (let s = o.materials.length - 1; s >= 0; --s)
-                o.materials[s].dispose();
-            const a = [];
-            for (let s = 0; s < o.meshes.length; ++s)
-                o.meshes[s].visibility = 0,
-                o.meshes[s].isPickable = !0,
-                o.meshes[s].checkCollisions = !1,
-                o.meshes[s].material = this.videoMat,
-                "hasVertexAlpha"in o.meshes[s] && (o.meshes[s].hasVertexAlpha = !1),
-                this.scene.addMesh(o.meshes[s]),
-                a.push(new XStaticMesh({
-                    id: o.meshes[s].id,
-                    mesh: o.meshes[s],
+        Promise.reject(new XTvModelError("[Engine] changeTvModel: videoMat is null or undefined!"))) : this._scenemanager.urlTransformer(this.meshPath).then(s=>new Promise((c,_)=>BABYLON.SceneLoader.LoadAssetContainerAsync("", s, this.scene, null, ".glb").then(b=>{
+            for (let j = b.materials.length - 1; j >= 0; --j)
+                b.materials[j].dispose();
+            const k = [];
+            for (let j = 0; j < b.meshes.length; ++j)
+                b.meshes[j].visibility = 0,
+                b.meshes[j].isPickable = !0,
+                b.meshes[j].checkCollisions = !1,
+                b.meshes[j].material = this.videoMat,
+                "hasVertexAlpha"in b.meshes[j] && (b.meshes[j].hasVertexAlpha = !1),
+                this.scene.addMesh(b.meshes[j]),
+                k.push(new XStaticMesh({
+                    id: b.meshes[j].id,
+                    mesh: b.meshes[j],
                     xtype: EMeshType.Tv
                 }));
-            e != "" && this.cleanTv(!1, !1),
-            this.tvMeshs = a,
+            o != "" && this.cleanTv(!1, !1),
+            this.tvMeshs = k,
             this.changeTvFitMode(),
-            r(this)
+            GEngine.engineOption.bDisableLocalRender && this.toggle(!1),
+            c(this)
         }
-        ).catch(o=>{
-            logger.error("[Engine] changeTvModel: create Tv by input mesh error! " + o),
-            n(new XTvModelError("[Engine] changeTvModel: create Tv by input mesh error! " + o))
+        ).catch(b=>{
+            logger.error("[Engine] changeTvModel: create Tv by input mesh error! " + b),
+            _(new XTvModelError("[Engine] changeTvModel: create Tv by input mesh error! " + b))
         }
         )))
     }
     calWidthHeightScale() {
-        const e = [1e5, 1e5, 1e5]
-          , t = [-1e5, -1e5, -1e5];
-        for (let a = 0; a < this.tvMeshs.length; ++a)
-            if (this.tvMeshs[a].mesh.name != "__root__") {
-                const s = this.tvMeshs[a].mesh.getBoundingInfo().boundingBox.vectorsWorld;
-                for (let l = 0; l < s.length; ++l)
-                    e[0] > s[l].x && (e[0] = s[l].x),
-                    e[1] > s[l].y && (e[1] = s[l].y),
-                    e[2] > s[l].z && (e[2] = s[l].z),
-                    t[0] < s[l].x && (t[0] = s[l].x),
-                    t[1] < s[l].y && (t[1] = s[l].y),
-                    t[2] < s[l].z && (t[2] = s[l].z);
+        const o = [1e5, 1e5, 1e5]
+          , s = [-1e5, -1e5, -1e5];
+        for (let k = 0; k < this.tvMeshs.length; ++k)
+            if (this.tvMeshs[k].mesh.name != "__root__") {
+                const j = this.tvMeshs[k].mesh.getBoundingInfo().boundingBox.vectorsWorld;
+                for (let $ = 0; $ < j.length; ++$)
+                    o[0] > j[$].x && (o[0] = j[$].x),
+                    o[1] > j[$].y && (o[1] = j[$].y),
+                    o[2] > j[$].z && (o[2] = j[$].z),
+                    s[0] < j[$].x && (s[0] = j[$].x),
+                    s[1] < j[$].y && (s[1] = j[$].y),
+                    s[2] < j[$].z && (s[2] = j[$].z);
                 break
             }
-        const r = t[0] - e[0]
-          , n = t[1] - e[1]
-          , o = t[2] - e[2];
-        return Math.sqrt(r * r + o * o) / Math.abs(n)
+        const c = s[0] - o[0]
+          , _ = s[1] - o[1]
+          , b = s[2] - o[2];
+        return Math.sqrt(c * c + b * b) / Math.abs(_)
     }
-    cleanTv(e=!1, t=!0) {
+    cleanTv(o=!1, s=!0) {
         logger.warn("[Engine] cleanTV");
-        for (let r = 0; r < this.tvMeshs.length; ++r)
-            this.tvMeshs[r].dispose(e, t);
+        for (let c = 0; c < this.tvMeshs.length; ++c)
+            this.tvMeshs[c].dispose(o, s);
         this.tvMeshs = [],
         this.meshPath = ""
     }

+ 36 - 26
src/XVideoRawYUV.js

@@ -1,41 +1,51 @@
 export default class XVideoRawYUV {
-    constructor(e, t) {
-        E(this, "scene");
-        E(this, "_videoRawYUVTexture");
-        E(this, "videosResOriArray");
-        E(this, "_currentVideoId");
-        this.scene = e,
+    constructor(o, s) {
+        this.scene = o,
         this._videoRawYUVTexture = [],
-        this.videosResOriArray = t,
+        this.videosResOriArray = s,
         this._currentVideoId = -1;
-        for (let r = 0; r < t.length; ++r)
-            (n=>{
-                const o = BABYLON.RawTexture.CreateLuminanceTexture(null, t[n].width, t[n].height * 1.5, this.scene, !1, !0);
-                o.name = "videoTex_" + t[n].width + "_" + t[n].height,
-                this._videoRawYUVTexture.push(o)
+        for (let c = 0; c < s.length; ++c)
+            (_=>{
+                const b = BABYLON.RawTexture.CreateLuminanceTexture(null, s[_].width, s[_].height * 1.5, this.scene, !1, !0);
+                b.name = "videoTex_" + s[_].width + "_" + s[_].height,
+                this._videoRawYUVTexture.push(b)
             }
-            )(r)
+            )(c)
     }
-    inRange(e) {
-        return e >= 0 && e < this._videoRawYUVTexture.length
+    createNewTexture(o, s) {
+        o < 1 || s < 1 || (o = Math.round(o),
+        s = Math.round(s),
+        this.findId(o, s))
     }
-    getVideoYUVTex(e) {
-        return this.inRange(e) ? this._videoRawYUVTexture[e] : null
+    inRange(o) {
+        return o >= 0 && o < this._videoRawYUVTexture.length
     }
-
-    findId(width, height) {
-        let r = 0;
-        for (let n = 0; n < this.videosResOriArray.length; ++n)
-            if (this.videosResOriArray[n].width == width && this.videosResOriArray[n].height == height) {
-                r = n;
+    getVideoYUVTex(o) {
+        return this.inRange(o) ? this._videoRawYUVTexture[o] : null
+    }
+    findId(o, s) {
+        let c = -1;
+        for (let _ = 0; _ < this.videosResOriArray.length; ++_)
+            if (this.videosResOriArray[_].width == o && this.videosResOriArray[_].height == s) {
+                c = _;
                 break
             }
-        return r
+        if (c < 0) {
+            const _ = BABYLON.RawTexture.CreateLuminanceTexture(null, o, s * 1.5, this.scene, !1, !0);
+            _.name = "videoTex_" + o + "_" + s,
+            this._videoRawYUVTexture.push(_),
+            c = this._videoRawYUVTexture.length - 1,
+            this.videosResOriArray.push({
+                width: o,
+                height: s
+            })
+        }
+        return c
     }
     getCurrentVideoTexId() {
         return this._currentVideoId
     }
-    setCurrentVideoTexId(e) {
-        this._currentVideoId = e
+    setCurrentVideoTexId(o) {
+        this._currentVideoId = o
     }
 }

+ 123 - 56
src/Xverse.js

@@ -7,56 +7,74 @@ import RenderType from "./enum/RenderType.js"
 import Person from "./enum/Person.js"
 import LoggerLevels from "./enum/LoggerLevels.js"
 import Logger from "./Logger.js"
+import AssetsStorage from "./AssetsStorage.js"
+import {tracker} from "./Tracker.js"
 
-const logger = new Logger('4DMVS')
+const logger = new Logger('xverse')
 export default class Xverse{
-    constructor(e) {
-        e || (e = {});
-        const {onLog: t, env: r, appId: n, releaseId: o, subPackageVersion: a} = e;
-        this.NO_CACHE = !1,
-        this.env = r || "PROD",
-        this.SUB_PACKAGE_VERSION = a,
-        this.debug && logger.setLevel(LoggerLevels.Debug);
-        const s = this.pageSession = util.uuid();
-        
-        reporter.updateHeader({
-            pageSession: s
-        })
-
-        // reporter.updateReportUrl(REPORT_URL[this.env])
-
-        a && reporter.updateBody({
-            sdkVersion: a
-        })
-
+    constructor(o) {
+        this.debug = !1;
+        this.pageSession = null;
+        this.preload = null;
+        this.appId = null;
+        this.releaseId = null;
+        o || (o = {});
+        const {onLog: s, env: c, appId: _, releaseId: b, subPackageVersion: k, debug: j, useIndexedDb: $=!0, userId: _e} = o;
+        this.debug = j || !1,
+        AssetsStorage.USE_INDEXEDDB = $,
+        Xverse.env = c || "PROD",
+        Xverse.SUB_PACKAGE_VERSION = k;
+        //this.debug && Logger.setLevel(LoggerLevels.Debug);
+        const et = this.pageSession = util.uuid();
+        if (reporter.updateHeader({
+            pageSession: et
+        }),
+        reporter.updateReportUrl(REPORT_URL[Xverse.env]),
+        k && reporter.updateBody({
+            sdkVersion: k,
+            appId: _
+        }),
+        _e && reporter.updateHeader({
+            userId: _e
+        }),
         logger.infoAndReportMeasurement({
-            type: "sdkInit",
-            extraData: {
-                version: a,
-                enviroment: r,
-                pageSession: s
+            metric: "sdkInit",
+            startTime: Date.now(),
+            extra: {
+                version: k,
+                enviroment: c,
+                pageSession: et,
+                engineVersion: VERSION
             }
+        }),
+        logger.debug("debug mode:", this.debug),
+        reporter.on("report", tt=>{
+            s && s(tt)
+        }
+        ),
+        _) {
+            this.appId = _,
+            this.releaseId = b;
+            const tt = ModelManager.getInstance(_, b);
+            this.preload = new Preload(tt)
+        }
+        tracker.init({
+            appId: _,
+            debug: this.debug,
+            appEnv: c || "PROD"
+        }),
+        tracker.updateHeader({
+            sdkVersion: k
         })
 
-        logger.debug("debug mode:", this.debug)
-
-        reporter.on("report", l=>{
-            t && t(l)
-        })
-
-        if (n) {
-            this.appId = n,
-            this.releaseId = o;
-            const l = ModelManager.getInstance(n, o);
-            this.preload = new Preload(l)
-        }
+        o || (o = {})
     }
     get isSupported() {
-        return isSupported()
+        return util.isSupported()
     }
     disableLogUpload() {
         reporter.disable(),
-        logger.debug("logger upload has been disabled")
+        logger.debug("log upload has been disabled")
     }
     async getSkinList() {
         return []
@@ -70,21 +88,70 @@ export default class Xverse{
         }]
     }
 
-    async joinRoom(e) {
-        const t = e.pathName || "thirdwalk"
-          , r = e.rotationRenderType || RenderType.RotationVideo
-          , n = e.person || Person.Third
-          , o = new XverseRoom(le(oe({}, e), {
-            appId: e.appId || this.appId,
-            releaseId: e.releaseId || this.releaseId,
-            pageSession: this.pageSession,
-            isAllSync: !0,
-            rotationRenderType: r,
-            syncByEvent: !0,
-            pathName: t,
-            person: n,
-            role: e.role || "audience"
-        }));
-        return o.initRoom().then(()=>o)
+    async joinRoom(o) {
+        const {player: s, camera: c} = this.getConfigPosition()
+          , _ = new XverseRoom({
+            ...o,
+            pageSession: util.uuid(),
+            role: o.role || "audience",
+            hasAvatar: !0,
+            syncToOthers: !0,
+            prioritySync: !1,
+            removeWhenDisconnected: !0,
+            player: o.player || s,
+            camera: o.camera || c
+        });
+        return _.initRoom().then(()=>_).catch(b=>{
+            throw logger.infoAndReportMeasurement({
+                tag: o.viewMode,
+                startTime: _._startTime,
+                metric: "joinRoom",
+                error: b
+            }),
+            _.leave(),
+            b
+        }
+        )
     }
-};
+    getConfigPosition() {
+        const s = new window.URLSearchParams(location.search).get("meetingId")
+          , c = randomBirthPoints[0];
+        return s ? (this.addMeetingOrigin(),
+        {
+            player: {
+                position: {
+                    x: -4902,
+                    y: -35,
+                    z: 0
+                },
+                angle: {
+                    pitch: 0,
+                    yaw: -270,
+                    roll: 0
+                }
+            },
+            camera: {
+                position: {
+                    x: -5182,
+                    y: -35,
+                    z: 120
+                },
+                angle: {
+                    pitch: 0,
+                    yaw: -270,
+                    roll: 0
+                }
+            }
+        }) : c
+    }
+    addMeetingOrigin() {
+        const o = new URLSearchParams(window.location.search.replace("?", ""));
+        o.delete("from"),
+        o.append("from", "share");
+        const s = `${window.location.origin}${window.location.pathname}?${o.toString()}`;
+        window.history.replaceState({}, "", s)
+    }
+};
+
+Xverse.env = null;
+Xverse.SUB_PACKAGE_VERSION = null;

+ 414 - 378
src/XverseAvatar.js

@@ -6,510 +6,546 @@ import MotionType from "./enum/MotionType.js"
 import Queue from "./Queue.js"
 import Logger from "./Logger.js"
 import CoreBroadcastType from "./enum/CoreBroadcastType.js"
+import {tracker} from "./Tracker.js"
+import {xverseAvatarTools} from "./XverseAvatarTools.js"
+import ComponentItemType from "./enum/ComponentItemType.js"
 
-const logger = new Logger('4DMVS_Character')
+const logger = new Logger('xverse-avatar')
 export default class XverseAvatar extends EventEmitter {
-    constructor({userId, isHost, room, avatarId, isSelf, group=AvatarGroup.Npc}) {
+    constructor({userId: s, isHost: c, room: _, avatarId: b, isSelf: k, group: j=AvatarGroup.Npc}) {
         super();
-        this.xAvatar
-        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._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(list=>{
-            const avatarModel = list.find(u=>u.id === avatarId);
-            avatarModel && (this._avatarModel = avatarModel)
-        })
-    }
-
-    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,
-                    value: 0,
-                    type: "playAnimationStart"
-                })
-            });
-
-            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,
-                extraData: {
-                    loop: isLoop
-                },
-                type: "playAnimationEnd"
-            })
-        } catch (err) {
-            return logger.error(`[avatar: ${this.userId}] Play animation failed: ${animationName}`, err),
-            this.isSelf && logger.infoAndReportMeasurement({
-                tag: animationName,
-                type: "playAnimationEnd",
-                error: err,
-                extraData: {
-                    loop: isLoop
-                }
-            }),
-            Promise.reject(err)
+        this.xAvatar = null;
+        this._isHost = !1;
+        this._room = null;
+        this._withModel = !1;
+        this._userId = null;
+        this.group = AvatarGroup.User;
+        this.state = "idle";
+        this.isLoading = !0;
+        this._isMoving = !1;
+        this._isRotating = !1;
+        this._failed = !1;
+        this.disconnected = !1;
+        this._avatarId = null;
+        this.prioritySync = !1;
+        this.priority = EAvatarRelationRank.Stranger;
+        this.micStatus = 0;
+        this._avatarModel = null;
+        this._motionType = MotionType.Walk;
+        this.isSelf = !1;
+        this._lastAnimTraceId = "";
+        this.statusSyncQueue = new Queue(this);
+        this.extraInfo = {};
+        this.attachedEffects = new Set;
+        this.currentPathName = "";
+        this.setPosition = s=>{
+            var c, _;
+            !this._room.signal.isUpdatedYUV || (_ = (c = this.xAvatar) == null ? void 0 : c.movementComponent) == null || _.updatePosition(xverseAvatarTools.positionPrecisionProtect(s), !0)
         }
-    }
-
-    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`))
-
-        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();
-
-        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);
-
-            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))
+        this.setRotation = s=>{
+            var c;
+            !this._room.signal.isUpdatedYUV || (c = this.xAvatar) == null || c.setRotation(xverseAvatarTools.rotationPrecisionProtect(s))
+        };
+        this.stopAnimation = ()=>{
+            var s, c;
+            (c = (s = this.xAvatar) == null ? void 0 : s.controller) == null || c.stopAnimation()
+        };
+        this.avatarComponentsSync = s=>{
+            s = s.map(c=>({
+                type: c.type,
+                id: c.id
+            })),
+            this._room.actionsHandler.avatarComponentsSync(s)
+        };
+
+        (this, "hide", ()=>{
+            var s;
+            if ((s = this.xAvatar) != null && s.hide())
+                return Promise.resolve(`avatar: ${this.userId} hide success`);
+            {
+                const c = `avatar: ${this.userId} hide failed ${!this.xAvatar && "without instance: xAvatar"}`;
+                return logger.warn(c),
+                Promise.reject(c)
             }
-
-            await Promise.all(s)
-            this.emit("componentsChanged", {
-                components: this.avatarComponents,
-                mode
-            })
-            this.isSelf && logger.infoAndReportMeasurement({
-                tag: "changeComponents",
-                type: "changeComponents",
-                extraData: {
-                    inputComponents: avatarComponents,
-                    finalComponents: this.avatarComponents,
-                    mode: ChangeComponentsMode[mode]
-                }
-            })
-            return this.avatarComponents
-
-        } catch (error) {
-            this.isSelf && logger.infoAndReportMeasurement({
-                tag: "changeComponents",
-                type: "changeComponents",
-                error,
-                extraData: {
-                    inputComponents: avatarComponents,
-                    finalComponents: this.avatarComponents,
-                    mode: ChangeComponentsMode[mode]
-                }
-            })
-            return Promise.reject(error)
-        }
-    }
-
-    avatarComponentsSync = e=>{
-        e = e.map(t=>({
-            type: t.type,
-            id: t.id
-        })),
-        this._room.actionsHandler.avatarComponentsSync(e)
-    }
-
-    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)
         }
-    }
-
-    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)
+        );
+        this.show = async()=>{
+            var s;
+            return (s = this.xAvatar) == null ? void 0 : s.show()
+        };
+        this.sayTimer = null;
+        this._userId = s,
+        this._room = _,
+        this.isSelf = k || !1,
+        this._withModel = !!b,
+        this._isHost = c || !1,
+        this._avatarId = b,
+        this.group = j,
+        this._room.modelManager.getAvatarModel(b).then($=>{
+            $ && (this._avatarModel = $)
         }
+        ),
+        k && this._room.pathManager.currentAttitude && (this._motionType = this._room.pathManager.currentAttitude)
     }
-
     get avatarId() {
         return this._avatarId
     }
-
     get isRender() {
-        var e;
-        return !!((e = this.xAvatar) != null && e.isRender)
+        var s;
+        return !!((s = this.xAvatar) != null && s.isRender)
     }
-
     get isHidden() {
-        var e;
-        return !!((e = this.xAvatar) != null && e.isHide)
+        var s;
+        return !!((s = this.xAvatar) != null && s.isHide)
     }
-
     get motionType() {
         return this._motionType
     }
-
-    set motionType(e) {
-        this._motionType = e
+    set motionType(s) {
+        this._motionType = s
     }
     get nickname() {
-        var e;
-        return (e = this.xAvatar) == null ? void 0 : e.nickName
+        var s;
+        return (s = this.xAvatar) == null ? void 0 : s.nickName
     }
-
     get words() {
-        var e;
-        return (e = this.xAvatar) == null ? void 0 : e.words
+        var s;
+        return (s = this.xAvatar) == null ? void 0 : s.words
     }
-
     get isHost() {
         return this._isHost
     }
-
     get failed() {
         return this._failed
     }
-
     get scale() {
-        var e;
-        return (e = this.xAvatar) == null ? void 0 : e.scale
+        var s;
+        return (s = this.xAvatar) == null ? void 0 : s.scale
     }
-
     get animations() {
-        var e;
-        return !this.xAvatar || !this.xAvatar.controller ? [] : ((e = this.xAvatar) == null ? void 0 : e.getAvaliableAnimations()) || []
+        return this.animationList.map(c=>c.name)
+    }
+    get animationList() {
+        const s = this._avatarModel.componentList.find(c=>c.type === ComponentItemType.ANIMATION);
+        return s ? s == null ? void 0 : s.unitList : []
+    }
+    get pandentList() {
+        const s = this._avatarModel.componentList.find(c=>c.type === ComponentItemType.PENDANT);
+        return s ? s == null ? void 0 : s.unitList : []
+    }
+    _getAnimationIdByName(s) {
+        var _;
+        const c = (_ = this.animationList) == null ? void 0 : _.find(b=>b.name === s);
+        return c ? c.id : ""
+    }
+    _getPandentIdByName(s) {
+        var _;
+        const c = (_ = this.pandentList) == null ? void 0 : _.find(b=>b.name === s);
+        return c ? c.id : ""
     }
-
     get position() {
-        var e;
-        return (e = this.xAvatar) == null ? void 0 : e.position
+        var s;
+        return (s = this.xAvatar) == null ? void 0 : s.position
     }
-
     get rotation() {
-        var e;
-        return (e = this.xAvatar) == null ? void 0 : e.rotation
+        var s;
+        return (s = this.xAvatar) == null ? void 0 : s.rotation
     }
-
     get pose() {
         return {
             position: this.position,
             angle: this.rotation
         }
     }
-
     get id() {
         return this.userId
     }
-
     get isMoving() {
         return this._isMoving
     }
-
-    set isMoving(e) {
-        this._isMoving = e,
-        this.state = e ? "moving" : "idle"
+    set isMoving(s) {
+        this._isMoving = s,
+        this.state = s ? "moving" : "idle"
     }
-
     get isRotating() {
         return this._isRotating
     }
-
-    set isRotating(e) {
-        this._isRotating = e,
-        this.state = e ? "rotating" : "idle"
+    set isRotating(s) {
+        this._isRotating = s,
+        this.state = s ? "rotating" : "idle"
     }
-
     get withModel() {
         return this._withModel
     }
-
     get avatarComponents() {
-        var e;
-        return JSON.parse(JSON.stringify(((e = this.xAvatar) == null ? void 0 : e.clothesList) || []))
+        var s;
+        return JSON.parse(JSON.stringify(((s = this.xAvatar) == null ? void 0 : s.clothesList) || []))
     }
-
     get userId() {
         return this._userId
     }
-
     get removeWhenDisconnected() {
         return this.extraInfo && this.extraInfo.removeWhenDisconnected !== void 0 ? this.extraInfo.removeWhenDisconnected : !0
     }
-
-    setConnectionStatus(e) {
-        this.disconnected !== e && (this.disconnected = e,
-        e ? this.emit("disconnected") : this.emit("reconnected"),
-        logger.warn(`avatar ${this.userId} status changed, disconnected:`, e))
+    setConnectionStatus(s) {
+        this.disconnected !== s && (this.disconnected = s,
+        s ? this.emit("disconnected") : this.emit("reconnected"),
+        logger.warn(`avatar ${this.userId} status changed, disconnected:`, s))
     }
-
-    setScale(scaleNum) {
-        this.xAvatar == null || this.xAvatar.setScale(scaleNum > 0 ? scaleNum : 1)
+    setScale(s) {
+        var c;
+        this.scale !== s && ((c = this.xAvatar) == null || c.setScale(s > 0 ? s : 1))
     }
-
-    async playAnimation(aniData) {
-        const {animationName, loop: isLoop, extra} = aniData || {};
+    async playAnimation(s) {
+        const {animationName: c, loop: _, extra: b, noSync: k=!1} = s || {};
         if (this.isSelf) {
             if (this.isMoving)
                 try {
                     await this.stopMoving()
-                } catch (err) {
-                    return logger.error(`stopMoving error before playAnimation ${animationName}`, err),
-                    Promise.reject(`stopMoving error before playAnimation ${animationName}`)
+                } catch (j) {
+                    return logger.error(`stopMoving error before playAnimation ${c}`, j),
+                    Promise.reject(`stopMoving error before playAnimation ${c}`)
                 }
-            const data = {
-                info: {
-                    userId: this.userId,
-                    animation: animationName,
-                    loop: isLoop,
-                    extra: encodeURIComponent(extra || "")
-                },
-                broadcastType: CoreBroadcastType.PlayAnimation
-            };
-            this._room.avatarManager.broadcast.broadcast({ data })
+            if (!k) {
+                const j = {
+                    info: {
+                        userId: this.userId,
+                        animation: c,
+                        loop: _,
+                        extra: encodeURIComponent(b || "")
+                    },
+                    broadcastType: CoreBroadcastType.PlayAnimation
+                };
+                this._room.avatarManager.broadcast.broadcast({
+                    data: j
+                })
+            }
         }
-        return this.emit("animationStart", {
-            animationName,
-            extra: safeDecodeURIComponent(extra || "")
+        return this.isSelf && (this.emit("animationStart", {
+            animationName: c,
+            extra: safeDecodeURIComponent(b || "")
         }),
-        this._playAnimation(animationName, isLoop).then(()=>{
-            this.emit("animationEnd", {
-                animationName,
-                extra: safeDecodeURIComponent(extra || "")
+        tracker.trackEvent("playAnimation", {
+            animation: c
+        })),
+        this._playAnimation(c, _).then(()=>{
+            this.isSelf && this.emit("animationEnd", {
+                animationName: c,
+                extra: safeDecodeURIComponent(b || "")
             })
-        })
+        }
+        )
     }
-
-    async beforeChangeComponentsHook(e) {}
-
-    turnTo(e) {
+    async _playAnimation(s, c=!0, _=!1, b="Idle") {
+        var $;
+        const k = this._getAnimationIdByName(s);
+        if (!this._room.signal.isUpdatedYUV)
+            return;
+        if (this.state !== "idle" && !_)
+            return logger.warn(this.userId, "_playAnimation", s, "failed, state is not idle"),
+            Promise.resolve();
+        const j = Date.now();
+        try {
+            if (!(($ = this.xAvatar) != null && $.controller))
+                return Promise.reject(new InternalError(`[avatar: ${this.userId}] Play animation failed: ${s}, no controller`));
+            this.isSelf && setTimeout(()=>{
+                logger.infoAndReportMeasurement({
+                    tag: s,
+                    startTime: j,
+                    value: 0,
+                    metric: "playAnimationStart"
+                })
+            }
+            );
+            const _e = uuid$1();
+            if (this._lastAnimTraceId = _e,
+            await this.xAvatar.controller.playAnimation(k, c),
+            _e === this._lastAnimTraceId && !this.isMoving && !c && s !== b) {
+                const et = this._getAnimationIdByName(b);
+                this.xAvatar.controller.playAnimation(et, c).catch(tt=>{
+                    logger.error(`[avatar: ${this.userId}] Play animation failed [force idle]`, tt)
+                }
+                )
+            }
+            return this.isSelf && logger.infoAndReportMeasurement({
+                tag: s,
+                startTime: j,
+                extra: {
+                    loop: c
+                },
+                metric: "playAnimationEnd"
+            }),
+            Promise.resolve(_e)
+        } catch (_e) {
+            return logger.error(`[avatar: ${this.userId}] Play animation failed: ${s}`, _e),
+            this.isSelf && logger.infoAndReportMeasurement({
+                tag: s,
+                startTime: j,
+                metric: "playAnimationEnd",
+                error: _e,
+                extra: {
+                    loop: c
+                }
+            }),
+            Promise.reject(_e)
+        }
+    }
+    async changeComponents(s) {
+        var _e;
+        const {mode: c, endAnimation: _=""} = s || {}
+          , b = Date.now()
+          , k = JSON.parse(JSON.stringify(s.avatarComponents));
+        let j = avatarComponentsValidate(k, this._avatarModel);
+        const $ = Date.now();
+        return (_e = this._room) == null || _e.stats.functionTimeConsumingAdd("avatarComponentsValidate", $ - b),
+        !ChangeComponentsMode[c] && !j && (j = new ParamError(`changeComponents failed, mode: ${c} is invalid`)),
+        j ? (logger.error(j),
+        Promise.reject(j)) : this._changeComponents({
+            avatarComponents: k,
+            mode: c,
+            endAnimation: _
+        }).then(()=>{
+            this.isSelf && c !== ChangeComponentsMode.Preview && this.avatarComponentsSync(this.avatarComponents)
+        }
+        )
+    }
+    async _changeComponents(s) {
+        var k;
+        const {avatarComponents: c=[], mode: _} = s || {}
+          , b = Date.now();
+        try {
+            if (!this.xAvatar)
+                return Promise.reject(new InternalError("changeComponents failed, without instance: xAvatar"));
+            const j = await xverseAvatarTools.avatarComponentsModify(this._avatarModel, c, this._room)
+              , $ = []
+              , _e = await xverseAvatarTools.avatarComponentsParser(this._avatarModel, j, this.avatarComponents, this._room);
+            if (_e.length === 0)
+                return this.avatarComponents;
+            await this.beforeChangeComponentsHook(s);
+            for (const et of _e) {
+                const {id: tt, type: rt} = et;
+                rt !== ComponentItemType.ANIMATION && $.push((k = this.xAvatar) == null ? void 0 : k.addComponent(tt, rt))
+            }
+            return await Promise.all($),
+            this.emit("componentsChanged", {
+                components: this.avatarComponents,
+                mode: _
+            }),
+            this.isSelf && (logger.infoAndReportMeasurement({
+                tag: "changeComponents",
+                startTime: b,
+                metric: "changeComponents",
+                extra: {
+                    inputComponents: c,
+                    finalComponents: this.avatarComponents,
+                    mode: ChangeComponentsMode[_]
+                }
+            }),
+            tracker.trackEvent("changeComponents", {
+                code: Codes.Success,
+                components: _e.map(({id: et, type: tt})=>({
+                    id: et,
+                    type: tt
+                })),
+                mode: ChangeComponentsMode[_]
+            })),
+            this.avatarComponents
+        } catch (j) {
+            return this.isSelf && (logger.infoAndReportMeasurement({
+                tag: "changeComponents",
+                startTime: b,
+                metric: "changeComponents",
+                error: j,
+                extra: {
+                    inputComponents: c,
+                    finalComponents: this.avatarComponents,
+                    mode: ChangeComponentsMode[_]
+                }
+            }),
+            tracker.trackEvent("changeComponents", {
+                code: -1,
+                components: c,
+                mode: ChangeComponentsMode[_]
+            })),
+            Promise.reject(j)
+        }
+    }
+    async beforeChangeComponentsHook(s) {}
+    turnTo(s) {
         if (this._room.viewMode === "observer") {
-            this._room.sceneManager.cameraComponent.MainCamera.setTarget(ue4Position2Xverse(e.point));
+            this._room.sceneManager.cameraComponent.MainCamera.setTarget(ue4Position2Xverse(s.point));
             return
         }
-        return this._room.actionsHandler.turnTo(e).then(()=>{
+        return this._room.actionsHandler.turnTo(s).then(()=>{
             this.emit("viewChanged", {
-                extra: (e == null ? void 0 : e.extra) || ""
+                extra: (s == null ? void 0 : s.extra) || ""
             })
-        })
+        }
+        )
     }
-
-    async moveTo(e) {
-        const {point: t, extra: r=""} = e || {};
+    async moveTo(s) {
+        const {point: c, extra: _=""} = s || {};
         if (!this.position)
             return Promise.reject(new ParamError("avatar position is empty"));
-        if (typeof r != "string" || typeof r == "string" && r.length > 64) {
-            const a = "extra shoud be string which length less than 64";
-            return logger.warn(a),
-            Promise.reject(new ParamError(a))
+        if (typeof _ != "string" || typeof _ == "string" && _.length > 64) {
+            const j = "extra shoud be string which length less than 64";
+            return logger.warn(j),
+            Promise.reject(new ParamError(j))
         }
-        const o = util.getDistance(this.position, t) / 100 > 100 ? MotionType.Run : MotionType.Walk;
+        const k = getDistance(this.position, c) / 100 > 100 ? MotionType.Run : MotionType.Walk;
         return this._room.actionsHandler.moveTo({
-            point: t,
-            motionType: o,
-            extra: r
+            point: c,
+            motionType: k,
+            extra: _
         })
     }
-
     async stopMoving() {
-        return this._room.actionsHandler.stopMoving()
-    }
-
-    rotateTo(e) {
-        return this._room.actionsHandler.rotateTo(e)
-    }
-
-    setRayCast(e) {
-        this.xAvatar && (this.xAvatar.isRayCastEnable = e)
-    }
-
-    say(e, t) {
-        if (this.sayTimer && window.clearTimeout(this.sayTimer),
+        if (!!this.isMoving)
+            return this._room.actionsHandler.stopMoving()
+    }
+    rotateTo(s) {
+        return this._room.actionsHandler.rotateTo(s)
+    }
+    setRayCast(s) {
+        this.xAvatar && (this.xAvatar.isRayCastEnable = s)
+    }
+    say(s, c, _) {
+        logger.debug("invoke avatar say", s, c, _);
+        let b, k, j, $;
+        if (typeof c == "object" ? (b = c.duration,
+        k = c.background,
+        j = c.fontSize,
+        $ = c.fontColor) : typeof c == "number" && (b = c),
+        this.sayTimer && window.clearTimeout(this.sayTimer),
         !this.xAvatar) {
             logger.error("say failed, without instance: xAvatar");
             return
         }
-        this.xAvatar.say(e, {
+        const _e = Object.assign({
             scale: this.xAvatar.scale,
-            isUser: this.group === AvatarGroup.User
-        }),
-        !(t === void 0 || t <= 0) && (this.sayTimer = window.setTimeout(()=>{
+            isUser: this.group === AvatarGroup.User,
+            background: k,
+            fontsize: j,
+            fontcolor: $
+        }, _ || {});
+        this.xAvatar.say(s, _e),
+        !(b === void 0 || b <= 0) && (this.sayTimer = window.setTimeout(()=>{
             this.silent()
         }
-        , t))
+        , b))
     }
-
     silent() {
-        var e;
+        var s;
         if (!this.xAvatar) {
             logger.error("silent failed, without instance: xAvatar");
             return
         }
-        (e = this.xAvatar) == null || e.silent()
-    }
-
-    setMotionType({type: e=MotionType.Walk}) {
-        return this.motionType === e ? Promise.resolve() : this._room.actionsHandler.setMotionType(e).then(()=>{
-            this._motionType = e
-        }
-        )
+        (s = this.xAvatar) == null || s.silent()
     }
-
-    setNickname(e) {
-        return this._room.actionsHandler.setNickName(encodeURIComponent(e))
+    setNickname(s) {
+        return this._room.actionsHandler.setNickName(encodeURIComponent(s))
     }
-
-    _setNickname(e) {
-        var r, n;
-        if (!e)
+    _setNickname(s, c={}) {
+        var b, k;
+        if (!s)
             return;
-        const t = safeDecodeURIComponent(e);
-        ((r = this.xAvatar) == null ? void 0 : r.nickName) !== t && (this.isSelf && (this._room.updateCurrentNetworkOptions({
-            nickname: t
+        const _ = safeDecodeURIComponent(s);
+        ((b = this.xAvatar) == null ? void 0 : b.nickName) !== _ && (this.isSelf && (this._room.updateCurrentNetworkOptions({
+            nickname: _
         }),
-        this._room.options.nickname = t),
-        (n = this.xAvatar) == null || n.setNickName(t, {
-            scale: this.xAvatar.scale
+        this._room.options.nickname = _),
+        (k = this.xAvatar) == null || k.setNickName(_, {
+            scale: this.xAvatar.scale,
+            ...c
         }))
     }
-
-    _move(e) {
-        var s;
-        const {start: t, end: r, walkSpeed: n, moveAnimation: o="Walking", inter: a=[]} = e || {};
-        return (s = this.xAvatar) == null ? void 0 : s.move(t, r, n, o, a)
+    _move(s) {
+        var rt;
+        const c = this.getMotionAnimtion("walk")
+          , _ = this._getAnimationIdByName(c)
+          , {start: b, end: k, walkSpeed: j, moveAnimation: $=_, inter: _e=[], enforceRaycast: et, backToIdle: tt} = s || {};
+        return (rt = this.xAvatar) == null ? void 0 : rt.move(b, k, j, $, _e, et, tt).then(()=>{
+            this.isMoving = !1
+        }
+        )
     }
-
-    setPickBoxScale(e=1) {
-        return this.xAvatar ? (this.xAvatar.setPickBoxScale(e),
+    moveHermite(s) {
+        var et;
+        const {start: c, end: _, moveAnimation: b=this.getMotionAnimtion("walk"), duration: k, tension: j, enforceRaycast: $, backToIdle: _e} = s || {};
+        return (et = this.xAvatar) == null ? void 0 : et.moveHermite(c, _, k, j, b, $, _e)
+    }
+    move(s) {
+        return this._move(s)
+    }
+    setPickBoxScale(s=1) {
+        return this.xAvatar ? (this.xAvatar.setPickBoxScale(s),
         !0) : (logger.error("setPickBoxScale failed, without instance: xAvatar"),
         !1)
     }
-
-    transfer(e) {
-        const {player: t, camera: r, areaName: n, attitude: o, pathName: a} = e;
+    transfer(s) {
+        const {player: c, camera: _, pathId: b} = s;
         return this._room.actionsHandler.transfer({
             renderType: RenderType.RotationVideo,
-            player: t,
-            camera: r,
-            areaName: n,
-            attitude: o,
-            pathName: a,
+            player: c,
+            camera: _,
+            pathId: b,
             tag: "transfer"
         })
     }
-
     avatarLoadedHook() {}
     avatarStartMovingHook() {}
     avatarStopMovingHook() {}
-
-    // 用于更新非MainAvatar的其他角色
-    async statusSync(userState) {
+    async statusSync(s) {
+        var c, _, b, k, j;
         try {
-            // 旋转
-            if (userState.event && userState.event.rotateEvent) 
-            {
-                const { angle, speed } = userState.event.rotateEvent
-                  , moveAnimation = this.motionType === MotionType.Run ? "Running" : "Walking";
-
-                this.rotation && (
-                    this.rotation.yaw = this.rotation.yaw % 360,
-                    angle.yaw - this.rotation.yaw > 180 && (angle.yaw = 180 - angle.yaw),
-                    this.isRotating = true,
-
-                    await this.xAvatar.rotateTo(angle, this.rotation, moveAnimation).then(()=>{
-                        this._playAnimation("Idle", true),
-                        this.isRotating = false
-                    })
-                )
+            if ((c = s.event) != null && c.rotateEvent) {
+                const {angle: $} = s.event.rotateEvent
+                  , _e = this.motionType === MotionType.Run ? "Running" : "Walking";
+                this.rotation && (this.rotation.yaw = this.rotation.yaw % 360,
+                $.yaw - this.rotation.yaw > 180 && ($.yaw = 180 - $.yaw),
+                this.isRotating = !0,
+                await this.xAvatar.rotateTo($, this.rotation, _e).then(()=>{
+                    this._playAnimation("Idle", !0),
+                    this.isRotating = !1
+                }
+                ))
             }
-
-            // 行走
-            if (userState.event && ((userState.event.points && userState.event.points.length) || 0) > 1 && !this.isSelf)
-            {
-                this.isMoving = true,
-                userState.playerState.attitude && (this._motionType = userState.playerState.attitude);
-
-                const moveAnimation = this.motionType === MotionType.Run ? "Running" : "Walking"
-                  , skinRoute = this._room.skin.routeList.find(l => l.areaName === this._room.currentState.areaName)
-                  , walkSpeed = ((skinRoute == null ? void 0 : skinRoute.step) || 7.5) * 30 * (25 / 30);
-
-                this.position && (
-                    await this._move({
-                        start: this.position,
-                        end: userState.event.points[userState.event.points.length - 1],
-                        walkSpeed,
-                        moveAnimation: moveAnimation,
-                        inter: userState.event && userState.event.points.slice(0, -1)
-                    }).then(()=>{
-                        this.isMoving = false
-                    })
+            if (((k = (b = (_ = s.event) == null ? void 0 : _.points) == null ? void 0 : b.length) != null ? k : 0) > 1) {
+                this.isMoving = !0,
+                s.playerState.attitude && (this._motionType = s.playerState.attitude);
+                const $ = this.getMotionAnimtion(this.motionType === MotionType.Run ? "run" : "walk")
+                  , _e = this._room.skin.pathList.find(tt=>tt.id === this.currentPathName)
+                  , et = ((_e == null ? void 0 : _e.step) || 7.5) * 25;
+                this.position && await this._move({
+                    start: this.position,
+                    end: s.event.points[s.event.points.length - 1],
+                    walkSpeed: et,
+                    moveAnimation: $,
+                    inter: (j = s.event) == null ? void 0 : j.points.slice(0, -1)
+                }).then(()=>{
+                    this.avatarStopMovingHook()
+                }
                 )
             }
         } catch {
             return
         }
     }
+    removeAttachedEffects() {
+        this.attachedEffects.forEach((s,c)=>{
+            this._room.effectManager.removeEffect(c)
+        }
+        ),
+        this.attachedEffects.clear()
+    }
+    removeAttachedEffect(s) {
+        this.attachedEffects.delete(s),
+        this._room.effectManager.removeEffect(s)
+    }
+    getMotionAnimtion(s) {
+        return MotionAnimtion[s] || MotionAnimtion.idle
+    }
+    faceTo({point: s, rotateSpeed: c=.1}) {
+        return this.xAvatar.faceTo(s, c)
+    }
 }

+ 458 - 315
src/XverseAvatarManager.js

@@ -1,9 +1,10 @@
 import CoreBroadcastType from "./enum/CoreBroadcastType.js"
 import AvatarGroup from "./enum/AvatarGroup.js"
+import ComponentItemType from "./enum/ComponentItemType.js"
 import Broadcast from "./Broadcast.js"
 import {avatarLoader} from "./XAvatarLoader.js"
 import SyncEventType from "./enum/SyncEventType.js"
-import GetStateTypes from "./enum/GetStateTypes.js"
+import PathType from "./enum/PathType.js"
 import EAvatarRelationRank from "./enum/EAvatarRelationRank.js"
 import Person from "./enum/Person.js"
 import XverseAvatar from "./XverseAvatar.js"
@@ -11,396 +12,538 @@ import MotionType from "./enum/MotionType.js"
 import TimeoutError from "./error/TimeoutError.js"
 import Logger from "./Logger.js"
 import QueueType from "./enum/QueueType.js"
+import AssetsStorage from "./AssetsStorage.js"
+import {xverseAvatarTools} from "./XverseAvatarTools.js"
+import InitEngineTimeoutError from "./error/InitEngineTimeoutError.js"
+import Actions from "./enum/Actions.js"
+import InternalError from "./error/InternalError.js"
 
 const logger = new Logger('4DMVS_CharacterManager')
 export default class XverseAvatarManager extends EventEmitter {
-    constructor(room) {
+    constructor(o) {
         super();
-        this.xAvatarManager = null
-        this.avatars = new Map
-        this.syncAvatarsLength = 0
-        this._room = room;
-        this._usersStatistics();
-        this.broadcast = this.setupBroadcast();
-        room.on("skinChanged", ()=>{
-            this.avatars.forEach(t=>{
-                avatar.disconnected && this.removeAvatar(avatar.userId, !0)
-            })
-        })
+        this.xAvatarManager = null;
+        this.avatars = new Map;
+        this.syncAvatarsLength = 0;
+        this.navmeshNavigationOpened = !0;
+        this.isNavmeshLoaded = !1;
+        this._room = o,
+        this._usersStatistics(),
+        this.broadcast = this.setupBroadcast()
     }
     setupBroadcast() {
-        return new Broadcast(this._room,async e=>{
-            const {broadcastType: t, info: r} = e;
-            if (t !== CoreBroadcastType.PlayAnimation)
+        return new Broadcast(this._room,async o=>{
+            const {broadcastType: s, info: c} = o;
+            if (s !== CoreBroadcastType.PlayAnimation)
                 return;
-            const {userId: n, animation: o, extra: a, loop: s=!1} = r
-              , l = this.avatars.get(n);
-            l && !l.isSelf && (l.emit("animationStart", {
-                animationName: o,
-                extra: decodeURIComponent(a)
+            const {userId: _, animation: b, extra: k, loop: j=!1} = c
+              , $ = this.avatars.get(_);
+            $ && !$.isSelf && ($.emit("animationStart", {
+                animationName: b,
+                extra: decodeURIComponent(k)
             }),
-            await (l == null ? void 0 : l._playAnimation(o, s)),
-            l.emit("animationEnd", {
-                animationName: o,
-                extra: decodeURIComponent(a)
+            await ($ == null ? void 0 : $._playAnimation(b, j)),
+            $.emit("animationEnd", {
+                animationName: b,
+                extra: decodeURIComponent(k)
             }))
         }
         )
     }
-    hideAll(e=!0) {
-        this.xAvatarManager.hideAll(e)
+    hideAll(o=!0) {
+        this.xAvatarManager.hideAll(o)
     }
-    showAll(e=!0) {
-        this.xAvatarManager.showAll(e)
+    showAll(o=!0) {
+        this.xAvatarManager.showAll(o)
+    }
+    setLodUserLimits(o, s) {
+        return this.xAvatarManager.setLodUserLimits(o, s)
     }
-
     async init() {
         this.xAvatarManager = this._room.sceneManager.avatarComponent;
         try {
-            const configList = await this._room.modelManager.getApplicationConfig()
-              , {avatars} = configList;
-            if (avatars) {
-                await avatarLoader.parse(this._room.sceneManager, avatars);
+            const o = await this._room.modelManager.getAvatarModelList()._timeout(6e3, new InitEngineTimeoutError("timeout when executing getAvatarModelList"));
+            if (o) {
+                await avatarLoader.parse(this._room.sceneManager, o)._timeout(6e3, new InitEngineTimeoutError("timeout when executing parse"));
                 return
             }
             return Promise.reject("cannot find avatar config list")
-        } catch (e) {
-            return logger.error(e),
-            Promise.reject("avatar mananger init error!")
+        } catch (o) {
+            return logger.error(o),
+            Promise.reject("avatar mananger init error!" + o)
         }
     }
-
-    async handleAvatar(signal) {
-        if (this._room.viewMode === "simple" || !this._room.joined || !signal.newUserStates)
+    async handleAvatar(o) {
+        if (this._room.viewMode === "simple" || !this._room.joined || !o.newUserStates)
             return;
-
-        let newUserStates = signal.newUserStates;
-        let userAvatar = this._room._userAvatar;
-        if ((userAvatar == null ? void 0 : userAvatar.isMoving) && userAvatar.motionType === MotionType.Run) 
-        {
-            const mainStates = newUserStates.filter(state => state.userId === this._room.userId)
-              , o = newUserStates.filter(state => state.userId !== this._room.userId).slice(0, 2);
-              newUserStates = mainStates.concat(o)
-        }
-
-        if (signal.getStateType === GetStateTypes.Event) 
-        {
-            this.syncAvatarsLength = (newUserStates || []).length;
-            const n = this._room.avatars.filter(avatar => avatar.group == AvatarGroup.User);
-            n.filter(avatar => 
-                !(newUserStates != null && newUserStates.find(state => state.userId == avatar.userId))
-            ).forEach(avatar=>{
-                this.removeAvatar(avatar.userId)
-            });
-            const a = newUserStates.filter(state => !n.find(avatar => avatar.userId == state.userId));
-            this._handleAvatar(a)
-        }
-        this._handleAvatar(newUserStates)
+        const s = o.newUserStates;
+        o.actionType === Actions.GetNewUserState ? (this.syncAvatarsLength = (s || []).length,
+        this._room.avatars.filter(b=>b.group == AvatarGroup.User).filter(b=>!(s != null && s.find(k=>k.userId == b.userId))).forEach(b=>this.removeAvatar(b.userId)),
+        this._handleAvatar(s, !0)) : this._handleAvatar(s, !1)
     }
-
-    async _handleAvatar(newUserStates) {
-
-        newUserStates && newUserStates.forEach(state=>{
-
-            const isMainAvatar = this._room.userId === state.userId;
-
-            if (state.event && state.event.type === SyncEventType.ET_RemoveVisitor) 
-            {
-                const removeVisitorEvent = state.event.removeVisitorEvent
-                const event =  removeVisitorEvent && removeVisitorEvent.removeVisitorEvent
-                  , extraInfo = JSON.parse(safeDecodeURIComponent((removeVisitorEvent && removeVisitorEvent.extraInfo) || ""))
-                  , { code, msg } = extraInfo;
-
-                  event === RemoveVisitorType.RVT_ChangeToObserver 
-                    ? this._room.audienceViewModeHook() 
-                    : event === RemoveVisitorType.RVT_MoveOutOfTheRoom && this._room.leave()      // 这里会触发Actions.Exit
-
-                this._room.emit("visitorStatusChanged", { code, msg })
+    async _handleAvatar(o, s) {
+        var b;
+        const c = Date.now();
+        o == null || o.forEach(k=>{
+            var $, _e, et, tt, rt, it, nt, at, ot, st, lt, ut;
+            const j = this._room.userId === k.userId;
+            if ((($ = k.event) == null ? void 0 : $.type) === SyncEventType.ET_RemoveVisitor) {
+                const ct = (et = (_e = k.event) == null ? void 0 : _e.removeVisitorEvent) == null ? void 0 : et.removeVisitorEvent
+                  , ht = JSON.parse(safeDecodeURIComponent(((rt = (tt = k.event) == null ? void 0 : tt.removeVisitorEvent) == null ? void 0 : rt.extraInfo) || ""))
+                  , {code: dt, msg: ft} = ht;
+                ct === RemoveVisitorType.RVT_ChangeToObserver ? this._room.audienceViewModeHook(ht) : ct === RemoveVisitorType.RVT_MoveOutOfTheRoom && this._room.leave(),
+                this._room.proxyEvents("kicked", {
+                    code: dt,
+                    msg: ft
+                }),
+                logger.warn("kicked emit: ", {
+                    code: dt,
+                    msg: ft
+                })
             }
-
-            if (state.event && [SyncEventType.Appear, SyncEventType.Reset].includes(state.event.type) || !state.event) {
-
-                let avatar = this.avatars.get(state.userId);
-                if(state.playerState.avatarId && avatar && avatar.avatarId !== state.playerState.avatarId) {
-                    avatar = void 0
-                    this.removeAvatar(state.userId)
-                }
-
-                if (avatar) {
-                    avatar.disconnected && avatar.setConnectionStatus(!1)
-                    state.event && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id)    // 这里会触发Actions.ConfirmEvent
-                    state.playerState.nickName && (avatar && avatar._setNickname(state.playerState.nickName))
-
-                    if (state.playerState.avatarComponents && !avatar.isSelf && avatar.xAvatar) {
-                        const avatarComponents = safeParseComponents(state.playerState.avatarComponents);
-                        // 这里会触发Actions.SetPlayerState
-                        avatar._changeComponents({
-                            avatarComponents,
+            if (k.event && [SyncEventType.Appear, SyncEventType.Reset].includes(k.event.type)) {
+                let ct = this.avatars.get(k.userId);
+                if (ct && k.playerState.avatarId && (ct == null ? void 0 : ct.avatarId) !== k.playerState.avatarId && (ct = void 0,
+                this.removeAvatar(k.userId, !0)),
+                ct) {
+                    if (ct.micStatus = k.playerState.micStatus || 0,
+                    typeof k.playerState.avatarSize == "number" && this._room.emit("avatarChanged", {
+                        avatars: this._room.avatars
+                    }),
+                    ct.isSelf) {
+                        const ht = this._room.currentState.pathId
+                          , dt = this._room.pathManager.currentAttitude
+                          , {attitude: ft, pathId: pt, skinId: gt} = k.playerState;
+                        if (pt && pt !== ht && (this._room.pathManager.currentPathName = pt,
+                        this._room.updateCurrentState({
+                            pathId: pt
+                        }),
+                        this._room.avatarManager.updateNavmesh({
+                            pathId: pt,
+                            skinId: gt
+                        }),
+                        this._room.modelManager.findPath(gt, pt).then(_t=>{
+                            _t && this._room.avatarManager.updateMoveStep(_t.step)
+                        }
+                        )),
+                        ft && ft !== dt) {
+                            const _t = this._room.skin.pathList.find(At=>At.id === this._room.currentState.pathId)
+                              , mt = ((_t == null ? void 0 : _t.step) || 7.5) * 30;
+                            this._room.updateCurrentState({
+                                speed: mt
+                            }),
+                            this._room.pathManager.currentAttitude = ft,
+                            ct.motionType = ft,
+                            (nt = (it = ct.xAvatar) == null ? void 0 : it.movementComponent) == null || nt.setMovementType(ft)
+                        }
+                    }
+                    if (k.playerState.pathName && (ct.currentPathName = k.playerState.pathName),
+                    ct.disconnected && ct.setConnectionStatus(!1),
+                    k.playerState.nickName && (ct == null || ct._setNickname(k.playerState.nickName)),
+                    k.playerState.avatarComponents && !ct.isSelf && ct.xAvatar) {
+                        const ht = xverseAvatarTools.safeParseComponents(k.playerState.avatarComponents);
+                        ct._changeComponents({
+                            avatarComponents: ht,
                             mode: ChangeComponentsMode.Preview
                         })
                     }
+                    if (!ct.isSelf && ct.position && (ct.statusSyncQueue.queue.length === 0 || !ct.statusSyncQueue.currentAction)) {
+                        const {x: ht, y: dt} = ct.position
+                          , {x: ft, y: pt} = k.playerState.player.position;
+                        (Math.abs(ht - ft) > 50 || Math.abs(dt - pt) > 50) && (ct.setPosition(k.playerState.player.position),
+                        ct.setRotation(k.playerState.player.angle))
+                    }
+                    if (k.playerState.extra && !s) {
+                        const ht = safelyJsonParse(k.playerState.extra)
+                          , dt = (at = ct.extraInfo) == null ? void 0 : at.saying;
+                        if (ct.extraInfo = {
+                            ...ct.extraInfo,
+                            ...ht
+                        },
+                        ht.saying || delete ct.extraInfo.saying,
+                        ct.extraInfo.saying) {
+                            if (JSON.stringify(ct.extraInfo.saying) !== JSON.stringify(dt)) {
+                                const {words: ft, options: pt} = (ot = ct.extraInfo) == null ? void 0 : ot.saying;
+                                ct.say(safeDecodeURIComponent(ft), pt)
+                            }
+                        } else
+                            dt && ct.silent()
+                    }
                 } else {
-                    const {position, angle} = state.playerState.player
-                      , avatarId = state.playerState.avatarId
-                      , prioritySync = state.playerState.prioritySync
-                      , extraInfo = safelyJsonParse(state.playerState.extra);
-                    if (!avatarId) return;
-
-                    const avatarComponents = safeParseComponents(state.playerState.avatarComponents)
-                      , nickname = safeDecodeURIComponent(state.playerState.nickName)
-                      , priority = this.calculatePriority(state.userId, extraInfo);
-                      
+                    if (!k.playerState.player)
+                        return;
+                    const {position: ht, angle: dt} = k.playerState.player
+                      , ft = k.playerState.avatarId
+                      , pt = k.playerState.prioritySync
+                      , gt = safelyJsonParse(k.playerState.extra)
+                      , _t = xverseAvatarTools.safeParseComponents(k.playerState.avatarComponents)
+                      , mt = safeDecodeURIComponent(k.playerState.nickName)
+                      , At = this.calculatePriority(k.userId, gt)
+                      , vt = (gt || {}).nicknameOptions;
                     this.addAvatar({
-                        userId: state.userId,
-                        isHost: state.playerState.isHost,
-                        nickname,
-                        avatarPosition: position,
-                        avatarRotation: angle,
-                        avatarScale: state.playerState.avatarSize,
-                        avatarId,
-                        avatarComponents: state.playerState.person === Person.First ? [] : avatarComponents,
-                        priority,
+                        userId: k.userId,
+                        isHost: k.playerState.isHost,
+                        nickname: mt,
+                        nicknameOptions: vt,
+                        avatarPosition: ht,
+                        avatarRotation: dt,
+                        avatarScale: k.playerState.avatarSize,
+                        avatarId: ft,
+                        avatarComponents: k.playerState.person === Person.First ? [] : _t,
+                        priority: At,
                         group: AvatarGroup.User,
-                        prioritySync,
-                        extraInfo
+                        prioritySync: pt,
+                        extraInfo: gt,
+                        currentPathName: k.playerState.pathId
                     }).then(()=>{
-                        state.event && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id),    // 这里会触发Actions.ConfirmEvent
-                        this.updateAvatarPositionAndRotation(state),
-                        isMainAvatar && (
-                            this.xAvatarManager.setMainAvatar(state.userId),
-                            this._room.emit("userAvatarLoaded"),
-                            logger.info("userAvatarLoaded")
-                        )
-                    }).catch(e=>{
-                        isMainAvatar && (
-                            this.xAvatarManager.setMainAvatar(state.userId),
-                            this._room.emit("userAvatarFailed", {error: e}),
-                            logger.error("userAvatarFailed", e)
-                        )
-                    })
+                        this.updateAvatarPositionAndRotation(k),
+                        j && (this._room.emit("userAvatarLoaded"),
+                        logger.info("userAvatarLoaded"))
+                    }
+                    ).catch(Et=>{
+                        j && (this._room.emit("userAvatarFailed", {
+                            error: Et
+                        }),
+                        logger.error("userAvatarFailed", Et))
+                    }
+                    )
                 }
             }
-
-            if(state.event && SyncEventType.Disappear === state.event.type) { 
-                state.event.id && this._room.actionsHandler.confirmEvent(state.event.id)    // 这里会触发Actions.ConfirmEvent
-                this.removeAvatar(state.userId)
-            }
-
-            if (state.event && [SyncEventType.Move, SyncEventType.ChangeRenderInfo].includes(state.event.type) || !state.event) {
-                state.event && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id);    // 这里会触发Actions.ConfirmEvent
-                const avatar = this.avatars.get(state.userId);
-                avatar && avatar.withModel && !avatar.isLoading && this.updateAvatarPositionAndRotation(state)
-            }
-
-            if (!isMainAvatar && state.event && state.event.type === SyncEventType.Rotate) {
-                const avatar = this.avatars.get(state.userId);
-                avatar.statusSyncQueue.append({
-                    type: QueueType.Rotate,
-                    action: () => avatar.statusSync(state)
-                })
-            }
-        })
+            SyncEventType.Disappear === ((st = k.event) == null ? void 0 : st.type) && this.removeAvatar(k.userId),
+            (!k.event || [SyncEventType.Move, SyncEventType.ChangeRenderInfo].includes(k.event.type)) && this.updateAvatarPositionAndRotation(k),
+            !j && ((lt = k.event) == null ? void 0 : lt.type) === SyncEventType.Rotate && ((ut = this.avatars.get(k.userId)) == null || ut.statusSyncQueue.append({
+                type: QueueType.Rotate,
+                userState: k
+            }))
+        }
+        );
+        const _ = Date.now();
+        (b = this._room) == null || b.stats.functionTimeConsumingAdd("_handleAvatar", _ - c)
     }
-
-    calculatePriority(e, t) {
-        var n;
-        return e === this._room.userId ? EAvatarRelationRank.Self : (n = this._room.options.firends) != null && n.includes(e) ? EAvatarRelationRank.Friend : EAvatarRelationRank.Stranger
+    calculatePriority(o, s) {
+        var _;
+        return o === this._room.userId ? EAvatarRelationRank.Self : (_ = this._room.options.firends) != null && _.includes(o) ? EAvatarRelationRank.Friend : EAvatarRelationRank.Stranger
     }
-
-    updateAvatarPositionAndRotation(userState) 
-    {
-        if (userState.playerState && userState.playerState.player) 
-        {
-            let {position, angle} = userState.playerState.player;
-            const avatar = this.avatars.get(userState.userId);
-            if (!avatar) return;
-
-            position = positionPrecisionProtect(position)
-            angle = rotationPrecisionProtect(angle)
-            avatar.isSelf && !this._room.networkController.rtcp.workers.inPanoMode && (avatar.setPosition(position), avatar.setRotation(angle))
-            userState.event && (userState.event.points.length || 0) > 1 && !avatar.isSelf && avatar.statusSyncQueue.append({
-                type: QueueType.Move,
-                action: () => avatar.statusSync(userState)
-            })
-
-            if (userState.renderInfo && avatar.isSelf) {
-                const {isMoving, isRotating} = userState.renderInfo;
+    updateAvatarPositionAndRotation(o) {
+        var j, $;
+        if (!((j = o == null ? void 0 : o.playerState) != null && j.player))
+            return;
+        const s = this.avatars.get(o.userId);
+        if (!s || s.isLoading)
+            return;
+        const c = Date.now()
+          , {position: _, angle: b} = o.playerState.player;
+        if (s.isSelf) {
+            if (this._room.sceneManager.playerController.serverUpdatePlayerLocation(o.playerState.player.position),
+            !this._room.networkController.rtcp.workers.inPanoMode && !(this.navmeshNavigationOpened && this.isNavmeshLoaded) && (s.setPosition(_),
+            s.setRotation(b)),
+            o.renderInfo) {
+                const {isMoving: _e, isRotating: et} = o.renderInfo;
                 this._updateAvatarMovingStatus({
-                    id: userState.userId,
-                    isMoving: !!isMoving,
-                    isRotating: !!isRotating
+                    id: o.userId,
+                    isMoving: !!_e,
+                    isRotating: !!et
                 })
             }
-        }
+        } else
+            s.statusSyncQueue.append({
+                type: QueueType.Move,
+                userState: o
+            });
+        const k = Date.now();
+        ($ = this._room) == null || $.stats.functionTimeConsumingAdd("updateAvatarPositionAndRotation", k - c)
     }
-
-    async addAvatar({
-        userId, isHost, avatarPosition, avatarId, avatarRotation, nickname, avatarComponents=[], priority, group=AvatarGroup.Npc, 
-        avatarScale=DEFAULT_AVATAR_SCALE, extraInfo, prioritySync
-    }) {
-        const isSelf = userId === this._room.userId;
-        let avatar = this.avatars.get(userId);
-        if (avatar) return Promise.resolve(avatar);
-
-        avatar = new XverseAvatarManager.subAvatar({
-            userId,
-            isHost,
-            isSelf,
+    async addAvatar(o) {
+        var ct;
+        const {userId: s, isHost: c, avatarPosition: _, avatarId: b, avatarRotation: k, nickname: j, nicknameOptions: $, avatarComponents: _e=[], priority: et, group: tt=AvatarGroup.Npc, avatarScale: rt=DEFAULT_AVATAR_SCALE, extraInfo: it, prioritySync: nt, currentPathName: at=""} = o
+          , ot = s === this._room.userId;
+        let st = this.avatars.get(s);
+        if (st)
+            return Promise.resolve(st);
+        if (st = new XverseAvatarManager.subAvatar({
+            userId: s,
+            isHost: c,
+            isSelf: ot,
             room: this._room,
-            avatarComponents,
-            avatarId,
-            nickname,
-            group
-        });
-        this.avatars.set(userId, avatar);
-
-        if (!avatar.withModel) {
-            avatar.isLoading = !1
-            avatar.avatarLoadedHook()
-            this._room.emit("avatarChanged", { avatars: this._room.avatars })
-            return avatar;
-        }
-
-        const avatarData = (await this._room.modelManager.getAvatarModelList()).find(data => data.id === avatarId)
-          , startTime = Date.now();
-        if (!avatarData) {
-            this._room.emit("avatarChanged", { avatars: this._room.avatars })
-            this.avatars.delete(userId)
-            return Promise.reject(`no such avatar model with id: ${avatarId}`);
-        }
-
+            avatarComponents: _e,
+            avatarId: b,
+            nickname: j,
+            group: tt
+        }),
+        this.avatars.set(s, st),
+        !st.withModel)
+            return st.isLoading = !1,
+            st.avatarLoadedHook(),
+            this._room.emit("avatarChanged", {
+                avatars: this._room.avatars
+            }),
+            st;
+        const lt = await this._room.modelManager.getAvatarModel(b)
+          , ut = Date.now();
+        if (!lt)
+            return this._room.emit("avatarChanged", {
+                avatars: this._room.avatars
+            }),
+            this.avatars.delete(s),
+            Promise.reject(`no such avatar model with id: ${b}`);
         try {
-            let b = await avatarComponentsModify(avatarData, avatarComponents);
-            b = b.filter(A=>A.type != "pendant");
-            
-            const assets = await avatarComponentsParser(avatarData, b)
-              , xAvatar = await this.xAvatarManager.loadAvatar({
-                id: userId,
-                avatarType: avatarId,
-                priority,
+            let ht = await xverseAvatarTools.avatarComponentsModify(lt, _e, this._room);
+            ht = ht.filter(pt=>pt.type != ComponentItemType.PENDANT);
+            const dt = await xverseAvatarTools.avatarComponentsParser(lt, ht, [], this._room)
+              , ft = await this.xAvatarManager.loadAvatar({
+                id: s,
+                avatarType: b,
+                priority: et,
                 avatarManager: this.xAvatarManager,
-                assets,
+                assets: dt,
                 status: {
-                    avatarPosition,
-                    avatarRotation,
-                    avatarScale
+                    avatarPosition: _,
+                    avatarRotation: k,
+                    avatarScale: rt
                 }
             })._timeout(8e3, new TimeoutError("loadAvatar timeout(8s)"));
-            xAvatar.setPickBoxScale(userId === this._room.userId ? 0 : 1);
-
-            avatar.xAvatar = xAvatar
-            avatar.setScale(avatarScale)
-            avatar.extraInfo = extraInfo
-            avatar.priority = priority
-            avatar.isLoading = !1
-            avatar.prioritySync = !!prioritySync
-            avatar._playAnimation("Idle", !0, !0)
-            avatar.avatarLoadedHook()
-            this._room.emit("avatarChanged", { avatars: this._room.avatars })
-            nickname && avatar._setNickname(nickname)
-
-            userId === this._room.userId && (
+            if (ft.controller.BindingAnimationId("Idle", st._getAnimationIdByName("Idle")),
+            ft.controller.BindingAnimationId("Running", st._getAnimationIdByName("Running")),
+            ft.controller.BindingAnimationId("Walking", st._getAnimationIdByName("Walking")),
+            st.xAvatar = ft,
+            st.extraInfo = it,
+            ft.setPickBoxScale(s === this._room.userId ? 0 : 1),
+            st.setScale(rt),
+            _ && st.setPosition(_),
+            st.priority = et,
+            st.isLoading = !1,
+            st.prioritySync = !!nt,
+            st._playAnimation("Idle", !0, !0),
+            st.currentPathName = at,
+            st.avatarLoadedHook(),
+            this._room.emit("avatarChanged", {
+                avatars: this._room.avatars
+            }),
+            j && st._setNickname(j, $),
+            s === this._room.userId) {
+                this.xAvatarManager.setMainAvatar(s);
+                const {skinId: pt, pathId: gt} = this._room.currentNetworkOptions;
+                this.registerOnMoveFinishedCallback(),
+                this.updateNavmesh({
+                    skinId: pt,
+                    pathId: gt
+                });
+                const _t = this._room.skin.pathList.find(mt=>mt.id === gt);
+                _t != null && _t.step && this.updateMoveStep(_t.step),
+                (ct = st.xAvatar.movementComponent) == null || ct.setMovementType(st.motionType),
+                this._room.sceneManager.playerController.updateServerAsyncThreshold(200),
+                this.setPlayerMovementLimit({
+                    uaxis: 1.1,
+                    vaxis: 2
+                }),
                 logger.infoAndReportMeasurement({
-                    type: "avatarLoadDuration",
+                    metric: "avatarLoadDuration",
+                    startTime: ut,
                     group: "costs"
                 }),
                 logger.infoAndReportMeasurement({
-                    type: "avatarLoadAt",
+                    metric: "avatarLoadAt",
+                    startTime: this._room._startTime,
                     group: "costs"
                 })
-            )
-            
-            return avatar
-        } catch (e) {
-            return avatar.isLoading = !1,
-            this._room.emit("avatarChanged", { avatars: this._room.avatars }),
-            logger.error(e),
-            Promise.reject(e)
+            }
+            return st
+        } catch (ht) {
+            return st.isSelf && this.xAvatarManager.setMainAvatar(st.userId),
+            st.isLoading = !1,
+            this._room.emit("avatarChanged", {
+                avatars: this._room.avatars
+            }),
+            logger.error(ht),
+            Promise.reject(ht)
         }
     }
-
-    removeAvatar(userId, t=!1) {
-        const avatar = this.avatars.get(userId);
-        if (!!avatar) {
-            if (avatar.removeWhenDisconnected || t) {
-                avatar.xAvatar && this.xAvatarManager.deleteAvatar(avatar.xAvatar),
-                this.avatars.delete(userId),
+    removeAvatar(o, s=!1) {
+        var b;
+        const c = Date.now()
+          , _ = this.avatars.get(o);
+        if (!!_) {
+            if (_.removeWhenDisconnected || s) {
+                _.removeAttachedEffects(),
+                _.xAvatar && this.xAvatarManager.deleteAvatar(_.xAvatar),
+                this.avatars.delete(o),
                 this._room.emit("avatarChanged", {
                     avatars: this._room.avatars
                 });
+                const k = Date.now();
+                (b = this._room) == null || b.stats.functionTimeConsumingAdd("removeAvatar", k - c);
                 return
             }
-            avatar.setConnectionStatus(!0)
+            _.setConnectionStatus(!0)
         }
     }
-
     clearOtherUsers() {
-        this.avatars.forEach(e=>{
-            !e.isSelf && e.group === AvatarGroup.User && this.removeAvatar(e.userId)
+        this.avatars.forEach(o=>{
+            !o.isSelf && o.group === AvatarGroup.User && this.removeAvatar(o.userId)
         }
         )
     }
-
-    async _updateAvatarMovingStatus(e) {
-        const {id: t, isMoving: r, isRotating: n} = e
-          , o = this.avatars.get(t);
-        if (!!o) {
-            if (o.isRotating !== n) {
-                o.isRotating = n;
-                let a = "Idle";
-                n && (a = "Walking",
-                o.motionType === MotionType.Run && (a = "Running")),
-                o._playAnimation(a, !0, !0),
-                logger.infoAndReportMeasurement({
-                    value: 0,
-                    type: n ? "userAvatarStartRotating" : "userAvatarStopRotating",
-                    extraData: {
-                        motionType: o.motionType,
-                        moveToExtra: this._room.moveToExtra
-                    }
-                })
-            }
-            if (o.isMoving !== r) {
-                o.isMoving = r;
-                let a = "Idle";
-                r && (a = "Walking",
-                o.motionType === MotionType.Run && (a = "Running")),
-                r ? (o.avatarStartMovingHook(),
-                o.emit("startMoving", {
-                    target: o,
-                    extra: this._room.moveToExtra
-                })) : (o.avatarStopMovingHook(),
-                o.emit("stopMoving", {
-                    target: o,
-                    extra: this._room.moveToExtra
-                })),
-                o._playAnimation(a, !0, !0),
-                logger.infoAndReportMeasurement({
-                    value: 0,
-                    type: r ? "userAvatarStartMoving" : "userAvatarStopMoving",
-                    extraData: {
-                        motionType: o.motionType,
-                        moveToExtra: this._room.moveToExtra
-                    }
-                })
-            }
+    async _updateAvatarMovingStatus(o) {
+        var $;
+        const s = Date.now()
+          , {id: c, isMoving: _, isRotating: b} = o
+          , k = this.avatars.get(c);
+        if (!k)
+            return;
+        if (k.isRotating !== b) {
+            k.isRotating = b;
+            let _e = k.getMotionAnimtion("idle");
+            b && (_e = k.getMotionAnimtion("walk"),
+            k.motionType === MotionType.Run && (_e = k.getMotionAnimtion("run"))),
+            this.navmeshNavigationOpened && this.isNavmeshLoaded || k._playAnimation(_e, !0, !0),
+            logger.infoAndReportMeasurement({
+                startTime: Date.now(),
+                value: 0,
+                metric: b ? "userAvatarStartRotating" : "userAvatarStopRotating",
+                extra: {
+                    motionType: k.motionType,
+                    moveToExtra: this._room.moveToExtra
+                }
+            })
+        }
+        if (k.isMoving !== _) {
+            k.isMoving = _;
+            let _e = k.getMotionAnimtion("idle");
+            _ && (_e = k.getMotionAnimtion("walk"),
+            k.motionType === MotionType.Run && (_e = k.getMotionAnimtion("run"))),
+            _ ? (k.avatarStartMovingHook(),
+            k.isSelf && k.emit("startMoving", {
+                target: k,
+                extra: this._room.moveToExtra
+            })) : (k.avatarStopMovingHook(),
+            k.isSelf && k.emit("stopMoving", {
+                target: k,
+                extra: this._room.moveToExtra
+            })),
+            this.navmeshNavigationOpened && this.isNavmeshLoaded || k._playAnimation(_e, !0, !0),
+            logger.infoAndReportMeasurement({
+                startTime: Date.now(),
+                value: 0,
+                metric: _ ? "userAvatarStartMoving" : "userAvatarStopMoving",
+                extra: {
+                    motionType: k.motionType,
+                    moveToExtra: this._room.moveToExtra
+                }
+            })
         }
+        const j = Date.now();
+        ($ = this._room) == null || $.stats.functionTimeConsumingAdd("_updateAvatarMovingStatus", j - s)
     }
     _usersStatistics() {
-        this.on("userAvatarLoaded", ()=>{
+        this._room.on("userAvatarLoaded", ()=>{
             window.setInterval(()=>{
-                const e = this._room.avatars.filter(r=>r.group === AvatarGroup.User).length || 0
-                  , t = this._room.avatars.filter(r=>r.group === AvatarGroup.User && r.isRender).length || 0;
+                const o = this._room.avatars.filter(c=>c.group === AvatarGroup.User).length || 0
+                  , s = this._room.avatars.filter(c=>c.group === AvatarGroup.User && c.isRender).length || 0;
                 this._room.stats.assign({
-                    userNum: e,
+                    userNum: o,
                     syncUserNum: this.syncAvatarsLength,
-                    renderedUserNum: t
+                    renderedUserNum: s
                 })
             }
             , 3e3)
         }
         )
     }
+    async _updateNavmesh({pathId: o, skinId: s}) {
+        var b, k;
+        const _ = (await this._room.modelManager.findAssetList(s)).find(j=>j.id === "navmesh");
+        if (!_) {
+            const j = `updateNavmesh failed, navMeshConfig not found, pathId: ${o}, skinId: ${s}`;
+            return logger.error(j),
+            Promise.reject(j)
+        }
+        try {
+            const j = await AssetsStorage.readOrRequest(_.url, {
+                returnBlob: !0
+            })._timeout(1e4, new InternalError("download navMesh timeout in 10s"))
+              , $ = (b = await new Response(j).json()) == null ? void 0 : b.navInfo
+              , _e = $ == null ? void 0 : $.find(et=>et.pathId === o);
+            if (!_e)
+                return Promise.reject("navmeshByPath not found");
+            (k = this._room.sceneManager) == null || k.playerController.updateNavmesh(_e);
+            return
+        } catch (j) {
+            const $ = `updateNavmesh failed, ${j}, pathId: ${o}, skinId: ${s}`;
+            return logger.error($),
+            Promise.reject($)
+        }
+    }
+    async updateNavmesh({pathId: o, skinId: s}) {
+        var b, k, j;
+        const c = await this._room.modelManager.findPath(s, o)
+          , _ = await this.needNavmesh(c);
+        if (this.navmeshNavigationOpened = _,
+        !_) {
+            (j = (k = (b = this._room._userAvatar) == null ? void 0 : b.xAvatar) == null ? void 0 : k.controller) == null || j.RemoveTick();
+            return
+        }
+        return this._room._userAvatar ? this._updateNavmesh({
+            pathId: o,
+            skinId: s
+        }).then(()=>{
+            var $, _e, et, tt, rt, it;
+            (et = (_e = ($ = this._room._userAvatar) == null ? void 0 : $.xAvatar) == null ? void 0 : _e.controller) == null || et.RemoveTick(),
+            (it = (rt = (tt = this._room._userAvatar) == null ? void 0 : tt.xAvatar) == null ? void 0 : rt.controller) == null || it.ReceiveTick(),
+            this.isNavmeshLoaded = !0
+        }
+        ).catch($=>{
+            this.isNavmeshLoaded = !1;
+            const _e = new InternalError("updateNavmesh failed: " + $);
+            logger.error(_e),
+            this._room.emit("error", {
+                code: _e.code,
+                msg: _e.message
+            })
+        }
+        ) : Promise.reject("unable to update navmesh before avatar loaded")
+    }
+    updateMoveStep(o) {
+        var s, c, _, b;
+        !this._room._userAvatar || (logger.debug("updateMoveStep", o),
+        (c = (s = this._room._userAvatar) == null ? void 0 : s.xAvatar) != null && c.movementComponent && ((b = (_ = this._room.sceneManager) == null ? void 0 : _.playerController) == null || b.updateMoveStep(o)))
+    }
+    setPlayerMovementLimit(o) {
+        var s, c;
+        if (!this._room._userAvatar)
+            throw "user avatar not loaded";
+        typeof o.uaxis == "number" && ((s = this._room.sceneManager) == null || s.playerController.setMoveLimitInCameraUaxis(o.uaxis > 0 ? o.uaxis : 0)),
+        typeof o.vaxis == "number" && ((c = this._room.sceneManager) == null || c.playerController.setMoveLimitInCameraVaxis(o.vaxis > 0 ? o.vaxis : 0))
+    }
+    getPlayerMovementLimit() {
+        var o, s;
+        return {
+            uaxis: (o = this._room.sceneManager) == null ? void 0 : o.playerController.moveLimitInCameraUaxis,
+            vaxis: (s = this._room.sceneManager) == null ? void 0 : s.playerController.moveLimitInCameraVaxis
+        }
+    }
+    async needNavmesh(o) {
+        if (this._room.movingByClick)
+            return !1;
+        const {pathType: s, person: c} = o;
+        return s === PathType.RoamingPath && c === Person.Third
+    }
+    registerOnMoveFinishedCallback() {
+        const o = ()=>{
+            var c, _, b;
+            const s = (b = (_ = (c = this._room._userAvatar) == null ? void 0 : c.xAvatar) == null ? void 0 : _.movementComponent) == null ? void 0 : b.frameMovementData;
+            s && this._room.actionsHandler.JoystickLocal(s)
+        }
+        ;
+        this._room.sceneManager.playerController.registerOnMoveFinished(o)
+    }
+    setMovementTriggerMode(o) {
+        this._room.movingByClick = o === "click";
+        const {skinId: s, pathId: c} = this._room.currentState;
+        this.updateNavmesh({
+            skinId: s,
+            pathId: c
+        })
+    }
 };
 
-E(XverseAvatarManager, "subAvatar", XverseAvatar);
+XverseAvatarManager.subAvatar = XverseAvatar;

+ 53 - 29
src/XverseEffectManager.js

@@ -1,44 +1,68 @@
 import Logger from "./Logger.js"
+import XverseEffect from "./XverseEffect.js"
 
-const logger = new Logger('4DMVS_EffectManager')
+const logger = new Logger('xverse-effect-manager')
 export default class XverseEffectManager extends EventEmitter {
-    constructor(e) {
+    constructor(s) {
         super();
-        E(this, "effects", new Map);
-        E(this, "room");
-        this.room = e
+        this.effects = new Map;
+        this.room = s
     }
-    async addEffect(e) {
-        var o;
-        const {jsonPath: t, id: r, type: n=IEffectType.SubSequence} = e;
+    async addEffect(s) {
+        const {jsonPath: c, id: _, type: b=IEffectType.SubSequence, clone: k} = s;
         try {
-            this.effects.get(r) && ((o = this.effects.get(r)) == null || o.dispose());
-            const a = new Ae.subEffect({
-                id: r,
-                jsonPath: t,
-                type: n,
-                room: this.room
-            });
-            return this.effects.set(r, a),
-            await a.init(),
-            a
-        } catch (a) {
-            return this.effects.delete(r),
-            logger.error(a),
-            Promise.reject(a)
+            let j = this.effects.get(_);
+            if (j && !k)
+                return j;
+            if (j && k)
+                j = j.clone();
+            else if (!j && k) {
+                const $ = new mr.subEffect({
+                    id: _,
+                    jsonPath: c,
+                    type: b,
+                    room: this.room
+                });
+                this.effects.set($.id, $),
+                j = $.clone()
+            } else
+                j = new mr.subEffect({
+                    id: _,
+                    jsonPath: c,
+                    type: b,
+                    room: this.room
+                });
+            return this.effects.set(j.id, j),
+            await j.init(),
+            j
+        } catch (j) {
+            return this.effects.delete(_),
+            logger.error(j),
+            Promise.reject(j)
         }
     }
     clearEffects() {
-        this.effects.forEach(e=>{
-            e.dispose(),
-            this.effects.delete(e.id)
+        this.effects.forEach(s=>{
+            this.removeEffect(s.id)
         }
         )
     }
-    removeEffect(e) {
-        const t = this.effects.get(e);
-        t == null || t.dispose(),
-        t && this.effects.delete(t.id)
+    removeEffect(s) {
+        const c = this.effects.get(s)
+          , _ = c == null ? void 0 : c.isFromClone;
+        if (c == null || c.dispose(),
+        c && this.effects.delete(c.id),
+        _) {
+            const b = c.id.split("_clone")[0]
+              , k = [];
+            this.effects.forEach(j=>{
+                j.id.startsWith(b) && j.id !== s && k.push(j.id)
+            }
+            ),
+            k.length == 1 && this.removeEffect(k[0])
+        }
     }
 }
 ;
+
+XverseEffectManager.subEffect = XverseEffect;

+ 518 - 8
src/XverseRoom.js

@@ -1,17 +1,527 @@
-import JoyStick from "./JoyStick.js"
-import Xverse_Room from "./Xverse_Room.js"
+import XRoom from "./XRoom.js";
+import JoyStick from "./JoyStick.js";
+import AvatarManager from "./AvatarManager.js";
+import Logger from "./Logger.js"
+import BreathPoint from "./BreathPoint.js"
 
-export default class XverseRoom extends Xverse_Room {
-    constructor(e) {
-        super(e);
+const logger = new Logger("XverseRoom");
+export default class XverseRoom extends XRoom {
+    constructor(s) {
+        super(s);
+        this.newsData = [];
+        this.breathPoint = null;
+        this.avatarManager = new AvatarManager(this)
         this.joyStick = new JoyStick(this)
+        this.decal = null;
+        this.canvas2 = null;
+        this.maxHeight = 516;
+        this.decal = null;
+
+        this.handlePress = s=>{
+            const {id: c, type: _} = s;
+            logger.info("longPress", s),
+            _ === EMeshType.XAvatar && this.emit("click", {
+                target: {
+                    name: "Avatar",
+                    id: c
+                }
+            })
+        };
+
+        this.handleClick = s=>{
+            const {id: c, type: _, point: b} = s;
+            if (!this.breathPoint.isMatched(s)) {
+                if (_ === EMeshType.XAvatar)
+                    return;
+                this.emit("click", {
+                    target: null
+                })
+            }
+        };
+
+        this.scaleUnit = s=>s * 1;
+        this.drawRoundedRect = (s,c,_,b,k,j,$,_e)=>{
+            const et = s;
+            if (typeof _e == "undefined" && (_e = !0),
+            typeof j == "undefined" && (j = 5),
+            typeof j == "number")
+                j = {
+                    tl: j,
+                    tr: j,
+                    br: j,
+                    bl: j
+                };
+            else {
+                const tt = {
+                    tl: 0,
+                    tr: 0,
+                    br: 0,
+                    bl: 0
+                };
+                for (const rt in tt)
+                    j[rt] = j[rt] || tt[rt]
+            }
+            et.beginPath(),
+            et.moveTo(c + j.tl, _),
+            et.lineTo(c + b - j.tr, _),
+            et.quadraticCurveTo(c + b, _, c + b, _ + j.tr),
+            et.lineTo(c + b, _ + k - j.br),
+            et.quadraticCurveTo(c + b, _ + k, c + b - j.br, _ + k),
+            et.lineTo(c + j.bl, _ + k),
+            et.quadraticCurveTo(c, _ + k, c, _ + k - j.bl),
+            et.lineTo(c, _ + j.tl),
+            et.quadraticCurveTo(c, _, c + j.tl, _),
+            et.closePath(),
+            $ && (et.fillStyle = $,
+            et.fill()),
+            _e && et.stroke()
+        };
+
+        this.drawRect = (s,c,_,b,k,j)=>{
+            s.fillStyle = j,
+            s.fillRect(this.scaleUnit(c), this.scaleUnit(_), this.scaleUnit(b), this.scaleUnit(k))
+        };
+    
+        this.drawFont = s=>{
+            const c = s.canvas
+              , _ = c.getContext("2d");
+            if (!_)
+                return;
+            const b = s.size || 10
+              , k = this.scaleUnit(b) + "px"
+              , j = s.color || "black"
+              , $ = s.family || '-apple-system, system-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
+              , _e = s.textBaseline || "top";
+            _.beginPath(),
+            _.fillStyle = j,
+            _.font = `${k} ${$}`,
+            _.textBaseline = _e,
+            this.wrapText({
+                canvas: c,
+                text: s.value,
+                x: this.scaleUnit(s.x),
+                y: this.scaleUnit(s.y),
+                maxWidth: s.maxWidth && this.scaleUnit(s.maxWidth),
+                maxHeight: s.maxHeight && this.scaleUnit(s.maxHeight),
+                lineHeight: s.lineHeight && this.scaleUnit(s.lineHeight),
+                noWrap: s.noWrap,
+                maxLines: s.maxLines
+            }),
+            _.closePath()
+        };
+  
+        this.wrapText = function(s) {
+            const {text: c, x: _, maxWidth: b=s.canvas && s.canvas.width || 300, maxHeight: k=s.maxHeight, lineHeight: j=s.canvas && parseInt(window.getComputedStyle(s.canvas).lineHeight) || parseInt(window.getComputedStyle(document.body).lineHeight), noWrap: $=!1} = s;
+            let {y: _e} = s;
+            if (typeof c != "string" || typeof _ != "number" || typeof _e != "number")
+                return;
+            const et = s.canvas.getContext("2d");
+            if (!et)
+                return;
+            const tt = c.split("")
+              , rt = et.measureText(c).width;
+            let it = ""
+              , nt = 1;
+            if (rt <= b) {
+                et.fillText(c, _, _e);
+                return
+            }
+            for (let at = 0; at < tt.length; at++) {
+                const ot = et.measureText(it).width
+                  , st = et.measureText(tt[at]).width;
+                if (ot + st > b) {
+                    if ($ || k && nt * j > k || s.maxLines && nt >= s.maxLines) {
+                        const lt = it.split("");
+                        lt.pop(),
+                        et.fillText(lt.join("") + "...", _, _e);
+                        break
+                    }
+                    et.fillText(it, _, _e),
+                    nt += 1,
+                    _e += j,
+                    it = tt[at]
+                } else
+                    et.measureText(tt.slice(at, tt.length - 1).join("")).width <= b ? (it += tt[at],
+                    at === tt.length - 1 && et.fillText(it, _, _e)) : it += tt[at]
+            }
+        };
+
+        this.getTextsHeight = (s,c,_,b,k)=>{
+            const j = c.split("");
+            let $ = ""
+              , _e = k;
+            s.beginPath();
+            const et = '-apple-system, system-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'
+              , tt = this.scaleUnit(_) + "px";
+            s.font = `${tt} ${et}`,
+            s.fillText("", 0, 0);
+            for (let rt = 0; rt < j.length; rt++) {
+                const it = $ + j[rt];
+                s.measureText(it).width > b && rt > 0 ? (_e += k,
+                $ = j[rt]) : $ = it
+            }
+            return s.closePath(),
+            _e
+        };
+
+        this.genereateCanvasImageSource = async s=>new Promise((c,_)=>{
+            const b = new Image;
+            b.src = s,
+            b.crossOrigin = "anonymous",
+            b.onload = ()=>{
+                c(b)
+            }
+            ,
+            b.onerror = k=>{
+                _(k)
+            }
+        }
+        );
+
+    }
+    get userAvatar() {
+        return this.avatars.find(s=>s.userId === this.userId)
+    }
+    get state() {
+        return this.networkController._state
+    }
+    get sessionId() {
+        return this.currentNetworkOptions.sessionId
+    }
+    beforeJoinRoomResolveHook() {
+        this.bindEvents(),
+        this.applyPlugin()
     }
     afterJoinRoomHook() {
         this.joyStick.init({
-            style: {
-                width: "150px",
-                height: "150px"
+            interval: 33
+        })
+    }
+    bindEvents() {
+        this.on("_coreClick", this.handleClick),
+        this.on("_corePress", this.handlePress)
+    }
+    async getImageUrlFromCanvas(s) {
+        return new Promise(function(c, _) {
+            s.toBlob(function(b) {
+                if (!b)
+                    return _("canvas to blob failed");
+                const k = URL.createObjectURL(b);
+                c(k)
+            })
+        }
+        )
+    }
+    async setNews(s) {
+        this.newsData = s;
+        const c = "\u8D34\u82B1";
+        this.canvas2 || (this.canvas2 = document.createElement("canvas"),
+        this.canvas2.style.width = "836px",
+        this.canvas2.style.height = this.maxHeight + "px",
+        this.canvas2.style.position = "absolute",
+        this.canvas2.style.top = "-99999px",
+        this.canvas2.style.left = "-99999px",
+        this.canvas2.id = "newsWallRenderCanvas",
+        document.body.appendChild(this.canvas2));
+        let _ = ""
+          , b = 0;
+        if (Array.isArray(s) ? (s.some($=>!$.title) && logger.error("\u5B58\u5728\u8BC4\u8BBA\u5185\u5BB9\u4E3A\u7A7A", s),
+        b = await this.renderNews(this.canvas2, s),
+        _ = await this.getImageUrlFromCanvas(this.canvas2)) : _ = s,
+        !_)
+            return 0;
+        const k = "commentWall";
+        if (!this.decal.decals.find($=>$.id === k)) {
+            const $ = await this.modelManager.findAsset("10149", c, "name");
+            await this.decal.addDecal({
+                id: k,
+                meshPath: $.url
+            })
+        }
+        return this.decal.setDecalTexture({
+            id: k,
+            buffer: _
+        }).then(()=>{
+            this.decal.toggle(k, !0)
+        }
+        ).catch($=>{
+            logger.error("\u8BBE\u7F6E\u8BC4\u8BBA\u5899\u5931\u8D25", $)
+        }
+        ),
+        b
+    }
+    async renderNews(s, c) {
+        const _ = s.getContext("2d");
+        if (!_)
+            return 0;
+        _.clearRect(0, 0, s.width, s.height);
+        const b = "rgba(102, 102, 102, 0.3)";
+        let k = 12;
+        const j = 22
+          , $ = 32
+          , et = 24 * 1.3
+          , tt = 210
+          , rt = tt / 3 * 4
+          , it = s.offsetWidth
+          , nt = s.offsetHeight;
+        s.width = this.scaleUnit(it),
+        s.height = this.scaleUnit(nt);
+        const at = async(lt,ut=j,ct=k)=>{
+            const ft = tt
+              , pt = 18
+              , gt = 12
+              , _t = 22
+              , mt = 32
+              , At = 24;
+            this.drawRoundedRect(_, ut, ct, 800, ft + 6 + gt + (gt - 6), 20, "#F3EFEC", !1);
+            try {
+                const vt = await this.genereateCanvasImageSource(lt.thumbnail[0] || defaultImg);
+                this.drawImage(_, vt, ut + pt, ct + gt, rt, tt)
+            } catch {
+                logger.error("render image error " + lt.thumbnail[0])
+            }
+            return this.drawFont({
+                canvas: s,
+                value: lt.title,
+                size: mt,
+                color: "#000000",
+                x: ut + rt + pt + 6,
+                y: ct + gt,
+                lineHeight: mt * 1.3,
+                maxWidth: 800 - (ut + rt + pt + 6),
+                maxHeight: 2 * mt * 1.3,
+                maxLines: 2
+            }),
+            this.drawFont({
+                canvas: s,
+                value: `${lt.source}  ${lt.datetime}`,
+                size: _t,
+                color: b,
+                x: ut + rt + pt + 6,
+                y: ct + gt + 2 * mt * 1.3,
+                maxWidth: 800 - (ut + rt + pt + 6),
+                noWrap: !0
+            }),
+            this.drawFont({
+                canvas: s,
+                value: lt.summary,
+                size: At,
+                color: "rgba(102, 102, 102, 0.5)",
+                lineHeight: et,
+                maxWidth: 800 - (ut + rt + pt + 6),
+                maxHeight: ft - mt * 1.3 * 2 - _t * 1.5,
+                x: ut + rt + pt + 6,
+                y: ct + gt + 2 * mt * 1.3 + _t + 6 * 2,
+                maxLines: 3
+            }),
+            ct + ft + 6 * 2
+        }
+        ;
+        try {
+            const lt = await this.genereateCanvasImageSource(bgImg);
+            this.drawImage(_, lt, 0, 0, it, nt)
+        } catch {
+            logger.error("render bgImage error"),
+            this.drawRect(_, 0, 0, it, nt, "#000000")
+        }
+        let ot = 0;
+        const st = this.maxHeight - k;
+        for (const [lt,ut] of c.entries()) {
+            const ct = await at(ut, j, k)
+              , ht = st - ct
+              , dt = c[lt + 1];
+            if (ot = lt,
+            dt) {
+                if (tt + $ > ht)
+                    return ot
+            } else
+                return ot;
+            k = ct + $
+        }
+        return ot
+    }
+    drawImage(s, c, _, b, k, j) {
+        s.drawImage(c, this.scaleUnit(_), this.scaleUnit(b), this.scaleUnit(k), this.scaleUnit(j))
+    }
+    applyPlugin() {
+        this.breathPoint = new BreathPoint(this)
+    }
+    async access(s, c) {
+        const {player: _, camera: b, areaName: k, attitude: j, pathName: $} = s;
+        return c === "access" ? this.panorama.access({
+            camera: b,
+            player: _,
+            areaName: k,
+            pathName: $,
+            attitude: j
+        }).then(()=>{
+            var _e;
+            (_e = this._userAvatar) == null || _e.hide(),
+            this.breathPoint.hideAll()
+        }
+        ) : this.panorama.exit({
+            camera: b,
+            player: _,
+            areaName: k,
+            pathName: $,
+            attitude: j
+        }).then(()=>{
+            this._userAvatar.show(),
+            this.breathPoint.showBreathPointInSkin("10149")
+        }
+        )
+    }
+    changeWorld(s, c) {
+        const {userId: _} = this.currentNetworkOptions
+          , b = "10149"
+          , {player: k, camera: j} = this.getPosition(c)
+          , {pathName: $, areaName: _e, attitude: et} = this.getRoute()
+          , tt = {
+            userId: _,
+            skinId: b,
+            mode: ChangeMode.Preview,
+            landingType: LandingType.NewPoint,
+            landingPoint: k,
+            landingCamera: j,
+            renderType: RenderType.RotationVideo,
+            pathName: $,
+            areaName: _e,
+            attitude: et,
+            person: Person.Third,
+            newWorldId: s
+        };
+        return console.log("start change world"),
+        this.actionsHandler.changeWorld(tt)
+    }
+    getRoute() {
+        const {pathName: s, areaName: c, attitude: _} = defaultConfig;
+        return {
+            pathName: s,
+            areaName: c,
+            attitude: _
+        }
+    }
+    getPosition(s) {
+        const c = randomBirthPoints[0];
+        return s ? {
+            player: {
+                position: {
+                    x: -547.84,
+                    y: -1120,
+                    z: 0
+                },
+                angle: {
+                    pitch: 0,
+                    yaw: 0,
+                    roll: 0
+                }
+            },
+            camera: {
+                position: {
+                    x: -547.84,
+                    y: -1120,
+                    z: 0
+                },
+                angle: {
+                    pitch: 0,
+                    yaw: 0,
+                    roll: 0
+                }
             }
+        } : c
+    }
+    async getUserList() {
+        const {userId: s} = this.currentNetworkOptions;
+        return await this.actionsHandler.getUserList({
+            userId: s
+        })
+    }
+    async transferToMeetingRoom() {
+        const s = {
+            position: {
+                x: -4902,
+                y: -35,
+                z: 0
+            },
+            angle: {
+                pitch: 0,
+                yaw: -90,
+                roll: 0
+            }
+        }
+          , c = {
+            position: {
+                x: -547.84,
+                y: -1120,
+                z: 0
+            },
+            angle: {
+                pitch: 0,
+                yaw: -90,
+                roll: 0
+            }
+        }
+          , _ = "thirdwalk"
+          , b = "49faba5d055a4836"
+          , k = MotionType.Walk;
+        this.userAvatar.transfer({
+            player: s,
+            camera: c,
+            areaName: _,
+            pathId: b,
+            attitude: k
+        }),
+        await this.userAvatar.playAnimation({
+            animationName: "Idle",
+            loop: !0
+        }),
+        this.networkController.rtcp.xStream.playStream()
+    }
+    async transferToFrontDesk() {
+        const s = {
+            position: {
+                x: -595.15,
+                y: -1.21,
+                z: 0
+            },
+            angle: {
+                pitch: 0,
+                yaw: 180,
+                roll: 0
+            }
+        }
+          , c = {
+            position: {
+                x: -595.15,
+                y: -1.21,
+                z: 100
+            },
+            angle: {
+                pitch: 0,
+                yaw: 180,
+                roll: 0
+            }
+        }
+          , _ = "thirdwalk"
+          , b = "thirdwalk"
+          , k = MotionType.Walk;
+        this.userAvatar.transfer({
+            player: s,
+            camera: c,
+            areaName: _,
+            pathName: b,
+            attitude: k
+        }),
+        await this.userAvatar.playAnimation({
+            animationName: "Idle",
+            loop: !0
+        })
+    }
+    setMicrophoneStatus(s) {
+        const {userId: c} = this.currentNetworkOptions;
+        return this.actionsHandler.setMicrophoneStatus({
+            userId: c,
+            microphoneStatus: s
         })
     }
 }

+ 0 - 572
src/Xverse_Room.js

@@ -1,572 +0,0 @@
-import XverseAvatarManager from "./XverseAvatarManager.js";
-import Codes from "./enum/Codes.js";
-import PathManager from "./PathManager.js";
-import Camera from "./Camera.js";
-import Stats from "./Stats.js";
-import ActionsHandler from "./ActionsHandler.js";
-import Signal from "./Signal.js";
-import ModelManager from "./ModelManager.js";
-import { reporter } from "./Reporter.js";
-import util from "./util.js";
-import XverseEffectManager from "./XverseEffectManager.js";
-import TimeoutError from "./error/TimeoutError.js";
-import ParamError from "./error/ParamError.js";
-import MotionType from "./enum/MotionType.js";
-import NetworkController from "./NetworkController.js";
-import InitNetworkTimeoutError from "./error/InitNetworkTimeoutError.js";
-import InitConfigTimeoutError from "./error/InitConfigTimeoutError.js";
-import InitDecoderTimeoutError from "./error/InitDecoderTimeoutError.js";
-import InitEngineError from "./error/InitEngineError.js";
-import { eventsManager } from "./EventsManager.js";
-import EngineProxy from "./EngineProxy.js";
-import EventsController from "./EventsController.js";
-import EImageQuality from "./enum/EImageQuality.js";
-import Panorama from "./Panorama.js";
-import Debug from "./Debug.js";
-import Logger from "./Logger.js";
-import NewUserStateType from "./enum/NewUserStateType.js";
-
-const logger = new Logger("4DMVS_Room");
-export default class Xverse_Room extends EventEmitter {
-  constructor(options) {
-    super();
-    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 = "";
-
-    this.options = options
-    this.options.wsServerUrl || (this.options.wsServerUrl = SERVER_URLS.DEV)
-    this.modelManager = ModelManager.getInstance(options.appId, options.releaseId)
-    this.updateReporter()
-
-    const n = options,
-      { canvas: t } = n,
-      r = Oe(n, ["canvas"]);
-
-    logger.infoAndReportMeasurement({
-      type: "startJoinRoomAt",
-      group: "joinRoom",
-      value: 0,
-      extraData: r
-    });
-  }
-
-  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 && data.signal &&
-        // console.error(data.signal.code, data.signal.actionResponses, data.signal.newUserStates)
-        // 更新坐标数据
-        this.signal.handleSignal(data, reject)
-        
-        // data.signal.newUserStates 
-        // && data.signal.newUserStates[0] 
-        // && data.signal.newUserStates[0].playerState 
-        // && data.signal.newUserStates[0].playerState.camera 
-        // && console.error(data.signal.newUserStates[0].playerState.camera.position, data.signal.newUserStates[0].playerState.camera.angle.yaw)
-      }),
-
-      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;
-  }
-  get viewMode() {
-    var e;
-    return ((e = this._currentState) == null ? void 0 : e.viewMode) || "full";
-  }
-  get id() {
-    return this._id;
-  }
-  get skinId() {
-    return this._currentState.skinId;
-  }
-  get skin() {
-    return this._currentState.skin;
-  }
-  get sessionId() {
-    return this.currentNetworkOptions.sessionId;
-  }
-  get pictureQualityLevel() {
-    return this.currentState.pictureQualityLevel;
-  }
-  get avatars() {
-    return Array.from(this.avatarManager.avatars.values());
-  }
-  get currentState() {
-    var e;
-    return le(oe({}, this._currentState), {
-      state: (e = this.networkController) == null ? void 0 : e._state,
-    });
-  }
-  get _userAvatar() {
-    return this.avatars.find((e) => e.userId === this.userId);
-  }
-  get tvs() {
-    return this.engineProxy._tvs;
-  }
-  get tv() {
-    return this.tvs[0];
-  }
-  get currentClickingState() {
-    return this._currentClickingState;
-  }
-  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 }),
-      reporter.updateBody({ roomId, role, skinId, avatarId, appId, wsServerUrl })
-  }
-
-  async initRoom() {
-    const { timeout: e = DEFAULT_JOINROOM_TIMEOUT } = this.options;
-    if (util.isSupported()) {
-      return this._initRoom()._timeout(e, new TimeoutError("initRoom timeout"));
-    } else {
-      return Promise.reject(new UnsupportedError());
-    }
-  }
-
-  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()
-  }
-
-  beforeJoinRoomResolve() {
-    this.setupStats(),
-      (this.eventsController = new EventsController(this)),
-      this.eventsController.bindEvents(),
-      (this.panorama = new Panorama(this)),
-      this.beforeJoinRoomResolveHook();
-  }
-  afterJoinRoom() {
-    (this.joined = !0),
-      this.viewMode === "observer" && this.setViewModeToObserver(),
-      logger.infoAndReportMeasurement({
-        tag: this.viewMode,
-        value: this.firstFrameTimestamp || Date.now() - this._startTime,
-        type: "joinRoom",
-        options: {
-          immediate: !0,
-        },
-      }),
-      (this.camera.initialFov =
-        this.sceneManager.cameraComponent.getCameraFov()),
-      this.stats.on("stats", ({ stats: e }) => {
-        reporter.report("stats", oe({}, e));
-      }),
-      (this.debug = new Debug(this)),
-      this.afterJoinRoomHook();
-    setInterval(() => {
-      this.actionsHandler
-        .getNewUserState(NewUserStateType.NUST_Undefined)
-        .then((i) => {
-          this.avatarManager.handleAvatar(i);
-        })
-        .catch(() => { });
-    }, 2e3);
-  }
-  afterReconnected() {
-    this.avatarManager.clearOtherUsers(), this.afterReconnectedHook();
-  }
-  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]
-  }
-
-  async initNetwork() {
-    if (this.viewMode === "serverless") return Promise.resolve();
-    const e = Date.now();
-    try {
-      await this.networkController
-        .connect()
-        ._timeout(8e3, new InitNetworkTimeoutError()),
-        logger.infoAndReportMeasurement({
-          type: "networkInitAt",
-          group: "joinRoom",
-        }),
-        logger.infoAndReportMeasurement({
-          type: "networkInitCost",
-          group: "joinRoom",
-        });
-    } catch (t) {
-      throw (
-        (logger.infoAndReportMeasurement({
-          type: "networkInitAt",
-          group: "joinRoom",
-          error: t,
-        }),
-          t)
-      );
-    }
-  }
-  async initConfig() {
-    const e = Date.now();
-    try {
-      await this.modelManager
-        .getApplicationConfig()
-        ._timeout(8e3, new InitConfigTimeoutError()),
-        logger.infoAndReportMeasurement({
-          type: "configInitAt",
-          group: "joinRoom",
-        }),
-        logger.infoAndReportMeasurement({
-          type: "configInitCost",
-          group: "joinRoom",
-        });
-    } catch (t) {
-      throw (
-        (logger.infoAndReportMeasurement({
-          type: "configInitAt",
-          group: "joinRoom",
-          error: t,
-        }),
-          t)
-      );
-    }
-  }
-  async initEngine(e) {
-    const t = Date.now();
-    try {
-      (this.engineProxy = new EngineProxy(this)),
-        await this.engineProxy.initEngine(e),
-        logger.infoAndReportMeasurement({
-          type: "webglInitAt",
-          group: "joinRoom",
-        }),
-        logger.infoAndReportMeasurement({
-          type: "webglInitCost",
-          group: "joinRoom",
-        });
-      return;
-    } catch (r) {
-      console.error(r)
-      let n = r;
-      return (
-        r.code !== Codes.InitEngineTimeout && (n = new InitEngineError()),
-        logger.error(r),
-        logger.infoAndReportMeasurement({
-          type: "webglInitAt",
-          group: "joinRoom",
-          error: n,
-        }),
-        Promise.reject(n)
-      );
-    }
-  }
-  async initWasm() {
-    if (this.viewMode === "serverless") return Promise.resolve();
-    const i = Date.now();
-    try {
-      await this.networkController.rtcp.workers
-        .init({
-          width: 1920,
-          height: 1080,
-          userID: this.userId,
-          pageSession: this.options.pageSession,
-          serverSession: "",
-        })
-        ._timeout(8e3, new InitDecoderTimeoutError()),
-        this.networkController.rtcp.workers.registerFunction("error", (o) => {
-          logger.error("decode error", o);
-          const { code: s, message: c } = o;
-          this.emit("error", {
-            code: s,
-            msg: c,
-          });
-        }),
-        logger.infoAndReportMeasurement({
-          type: "wasmInitAt",
-          group: "joinRoom"
-        }),
-        logger.infoAndReportMeasurement({
-          type: "wasmInitCost",
-          group: "joinRoom"
-        }),
-        eventsManager.on("traceId", (o) => {
-          this.networkController.rtcp.workers.onTraceId(o);
-        });
-    } catch (o) {
-      throw (
-        (logger.infoAndReportMeasurement({
-          type: "wasmInitAt",
-          group: "joinRoom",
-          error: o,
-        }),
-          o)
-      );
-    }
-  }
-  async requestCreateRoom({ skinId: e }) {
-    let skin;
-    if (e) {
-      skin = await this.getSkin(e);
-      this.updateCurrentState({
-        skin: skin,
-      });
-      const r = await this.modelManager.findRoute(e, this.options.pathName);
-      this.updateCurrentNetworkOptions({
-        areaName: r.areaName,
-        attitude: r.attitude,
-        versionId: skin.versionId,
-      });
-      const { camera: n, player: player } =
-        util.getRandomItem(r.birthPointList) || this.options;
-      this.options.camera ||
-        this.updateCurrentNetworkOptions({
-          camera: n,
-        }),
-        this.options.player ||
-        this.updateCurrentNetworkOptions({
-          player: player,
-        });
-    }
-    if (this.viewMode === "serverless") return skin;
-    try {
-      await this.beforeStartGameHook(this.options);
-      const {
-        room_id: room_id,
-        data: n,
-        session_id: session_id,
-      } = await this.networkController.startGame();
-      this._id = room_id;
-      const a = JSON.parse(n);
-      (this.isHost = a.IsHost), (e = a.SkinID || e);
-      const skin = await this.getSkin(e);
-      this.updateCurrentNetworkOptions({
-        roomId: room_id,
-        sessionId: session_id,
-      });
-      reporter.updateBody({
-        roomId: room_id,
-        skinId: e,
-        serverSession: session_id,
-      });
-      return skin;
-    } catch (r) {
-      logger.error("requestCreateRoom error:", r);
-      return Promise.reject(r);
-    }
-  }
-  pause() {
-    return this.engineProxy.pause();
-  }
-  resume() {
-    return this.engineProxy.resume();
-  }
-  reconnect() {
-    this.networkController.reconnect();
-  }
-  async setViewMode(e) { }
-  handleRepetLogin() {
-    logger.warn("receive " + Codes.RepeatLogin + " for repeat login"),
-      this.emit("repeatLogin"),
-      reporter.disable(),
-      this.networkController.quit();
-  }
-  setPictureQualityLevel(e) {
-    const t = {
-      high: EImageQuality.high,
-      low: EImageQuality.low,
-      average: EImageQuality.mid,
-    };
-    return (
-      this.updateCurrentState({
-        pictureQualityLevel: e,
-      }),
-      this.sceneManager.setImageQuality(t[e])
-    );
-  }
-  async getSkin(skinId) {
-    let t = (this.skinList = await this.modelManager.getSkinsList()).find(
-      (skin) => skin.id === skinId || skin.id === skinId
-    );
-    if (t) return t;
-    {
-      const n = `skin is invalid: skinId: ${skinId}`;
-      return Promise.reject(new ParamError(n));
-    }
-  }
-  setupStats() {
-    this.stats.assign({
-      roomId: this.id,
-      userId: this.userId,
-    }),
-      setInterval(this.engineProxy.updateStats, 1e3);
-  }
-  proxyEvents(e, t) {
-    this.emit(e, t);
-  }
-  setCurrentNetworkOptions(e) {
-    this._currentNetworkOptions = e;
-  }
-  updateCurrentNetworkOptions(e) {
-    Object.assign(this._currentNetworkOptions, e),
-      Object.assign(this.options, e);
-  }
-  setCurrentState(e) {
-    this._currentState = e;
-  }
-  updateCurrentState(e) {
-    e.skinId &&
-      ((this.lastSkinId = this.currentState.skinId),
-        this.updateCurrentNetworkOptions({
-          skinId: e.skinId,
-        })),
-      e.versionId &&
-      this.updateCurrentNetworkOptions({
-        versionId: e.versionId,
-      }),
-      Object.assign(this._currentState, e);
-  }
-
-  afterSetUrlHook() { }
-  afterTvStopedHook() { }
-  afterTvPlayedHook() { }
-  pageShowHandler() {
-    this.engineProxy.setEnv(this.skin), (this.allowRender = !0);
-  }
-  pageHideHandler() {
-    this.allowRender = !1;
-  }
-}

+ 0 - 29
src/defaultLog.js

@@ -1,29 +0,0 @@
-const DEFAULT_LOGGER = {
-    debug: console.log,
-    info: console.log,
-    warn: console.warn,
-    error: console.error
-}
-
-export default class defaultLog{
-    constructor(e) {
-        E(this, "module");
-        this.module = e
-    }
-    static setLogger(e) {
-        defaultLog.instance = e
-    }
-    debug(...e) {
-        return Logger1.instance.debug(...e)
-    }
-    info(...e) {
-        return Logger1.instance.info(...e)
-    }
-    warn(...e) {
-        return Logger1.instance.warn(...e)
-    }
-    error(...e) {
-        return Logger1.instance.error(...e)
-    }
-};
-E(defaultLog, "instance", DEFAULT_LOGGER);

+ 17 - 1
src/enum/Actions.js

@@ -9,6 +9,8 @@ var Actions = {
     GetOnVehicle:22,
     GetOffVehicle:23,
     StopMoving:34,
+    RotationEnd:35,
+    ChangeWorld:37,
     UnaryActionLine:1e3,
     Init:1001,
     Exit:1002,
@@ -34,6 +36,12 @@ var Actions = {
     GetUserWithAvatar:1023,
     GetNewUserState:1024,
     SetSyncPolicy:1025,
+    StartLive:1026,
+    SetMicStatus:1028,
+    JoystickLocal:1030,
+    SetJoystickBox:1031,
+    SetPriority:1032,
+    SetUserExtra:1033,
 
     1:'Clicking',
     6:'PlayCG',
@@ -45,6 +53,8 @@ var Actions = {
     22:'GetOnVehicle',
     23:'GetOffVehicle',
     34:'StopMoving',
+    35:'RotationEnd',
+    37:'ChangeWorld',
     1e3:'UnaryActionLine',
     1001:'Init',
     1002:'Exit',
@@ -69,6 +79,12 @@ var Actions = {
     1022:'RemoveVisitor',
     1023:'GetUserWithAvatar',
     1024:'GetNewUserState',
-    1025:'SetSyncPolicy'
+    1025:'SetSyncPolicy',
+    1026:'StartLive',
+    1028:'SetMicStatus',
+    1030:'JoystickLocal',
+    1031:'SetJoystickBox',
+    1032:'SetPriority',
+    1033:'SetUserExtra'
 }
 export default Actions

+ 4 - 1
src/enum/AssetTypeName.js

@@ -1,6 +1,9 @@
 var AssetTypeName = {
     Config:'CONFIG',
-    Model:'MODEL',
+    Model:'LPM',
+    TV:'TV',
+    DECAL: 'DECAL',
+    IMAGE: 'IMAGE',
     Vedio:'VEDIO',
     Media:'MEDIA',
     Effects:'EFFECTS',

+ 1 - 0
src/enum/BillboardStatus.js

@@ -1,6 +1,7 @@
 var BillboardStatus = {
     SHOW:1,
     HIDE:0,
+    CLEAR:2,
     DISPOSE:-1
 }
 export default BillboardStatus

+ 4 - 1
src/enum/Codes.js

@@ -14,6 +14,7 @@ var Codes = {
     ActionBlocked:1012,
     PreloadCanceled:1013,
     FrequencyLimit:1014,
+    ConnectingAlready:1015,
     UsersUpperLimit:2e3,
     RoomsUpperLimit:2001,
     ServerParam:2002,
@@ -33,6 +34,8 @@ var Codes = {
     ServerRateLimit:2020,
     DoActionBlocked:2333,
     ActionMaybeDelay:2334,
-    ActionResponseTimeout:2999,
+    UnReachable:2335,
+    AbnormalDataStructure:2998,
+    ActionResponseTimeout:2999
 }
 export default Codes

+ 0 - 1
src/index.js

@@ -1 +0,0 @@
-alert(2)

Diferenças do arquivo suprimidas por serem muito extensas
+ 823 - 4
src/main.js


+ 0 - 36
src/video/ShaderCompiler.js

@@ -1,36 +0,0 @@
-/**
- * Represents a WebGL shader object and provides a mechanism to load shaders from HTML
- * script tags.
- */
-
-export default class ShaderCompiler {
-  /**
-   * @param {WebGLRenderingContext}gl
-   * @param {{type: string, source: string}}script
-   * @return {WebGLShader}
-   */
-  static compile (gl, script) {
-    let shader
-    // Now figure out what type of shader script we have, based on its MIME type.
-    if (script.type === 'x-shader/x-fragment') {
-      shader = gl.createShader(gl.FRAGMENT_SHADER)
-    } else if (script.type === 'x-shader/x-vertex') {
-      shader = gl.createShader(gl.VERTEX_SHADER)
-    } else {
-      throw new Error('Unknown shader type: ' + script.type)
-    }
-
-    // Send the source to the shader object.
-    gl.shaderSource(shader, script.source)
-
-    // Compile the shader program.
-    gl.compileShader(shader)
-
-    // See if it compiled successfully.
-    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
-      throw new Error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader))
-    }
-
-    return shader
-  }
-}

+ 0 - 52
src/video/ShaderProgram.js

@@ -1,52 +0,0 @@
-export default class ShaderProgram {
-  /**
-   * @param {WebGLRenderingContext}gl
-   */
-  constructor (gl) {
-    this.gl = gl
-    this.program = this.gl.createProgram()
-  }
-
-  /**
-   * @param {WebGLShader}shader
-   */
-  attach (shader) {
-    this.gl.attachShader(this.program, shader)
-  }
-
-  link () {
-    this.gl.linkProgram(this.program)
-    // If creating the shader program failed, alert.
-    if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {
-      console.error('Unable to initialize the shader program.')
-    }
-  }
-
-  use () {
-    this.gl.useProgram(this.program)
-  }
-
-  /**
-   * @param {string}name
-   * @return {number}
-   */
-  getAttributeLocation (name) {
-    return this.gl.getAttribLocation(this.program, name)
-  }
-
-  /**
-   * @param {string}name
-   * @return {WebGLUniformLocation | null}
-   */
-  getUniformLocation (name) {
-    return this.gl.getUniformLocation(this.program, name)
-  }
-
-  /**
-   * @param {WebGLUniformLocation}uniformLocation
-   * @param {Array<number>}array
-   */
-  setUniformM4 (uniformLocation, array) {
-    this.gl.uniformMatrix4fv(uniformLocation, false, array)
-  }
-}

+ 0 - 50
src/video/ShaderSources.js

@@ -1,50 +0,0 @@
-/**
- * @type {{type: string, source: string}}
- */
-export const vertexQuad = {
-  type: 'x-shader/x-vertex',
-  source: `
-  precision mediump float;
-
-  uniform mat4 u_projection;
-  attribute vec2 a_position;
-  attribute vec2 a_texCoord;
-  varying vec2 v_texCoord;
-  void main(){
-      v_texCoord = a_texCoord;
-      gl_Position = u_projection * vec4(a_position, 0.0, 1.0);
-  }
-`
-}
-
-/**
- * @type {{type: string, source: string}}
- */
-export const fragmentYUV = {
-  type: 'x-shader/x-fragment',
-  source: `
-  precision lowp float;
-  
-  varying vec2 v_texCoord;
-  
-  uniform sampler2D yTexture;
-  uniform sampler2D uTexture;
-  uniform sampler2D vTexture;
-    
-  const mat4 conversion = mat4(
-    1.0,     0.0,     1.402,  -0.701,
-    1.0,    -0.344,  -0.714,   0.529,
-    1.0,     1.772,   0.0,    -0.886,
-    0.0,     0.0,     0.0,     0.0
-  );
-
-  void main(void) {
-    float yChannel = texture2D(yTexture, v_texCoord).x;
-    float uChannel = texture2D(uTexture, v_texCoord).x;
-    float vChannel = texture2D(vTexture, v_texCoord).x;
-    vec4 channels = vec4(yChannel, uChannel, vChannel, 1.0);
-    vec3 rgb = (channels * conversion).xyz;
-    gl_FragColor = vec4(rgb, 1.0);
-  }
-`
-}

+ 0 - 88
src/video/Texture.js

@@ -1,88 +0,0 @@
-// Copyright 2019 Erik De Rijcke
-//
-// This file is part of Greenfield.
-//
-// Greenfield is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Greenfield is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with Greenfield.  If not, see <https://www.gnu.org/licenses/>.
-
-/**
- * Represents a WebGL texture object.
- */
-export default class Texture {
-  /**
-   * @param {!WebGLRenderingContext}gl
-   * @param {!number}format
-   * @return {!Texture}
-   */
-  static create (gl, format) {
-    const texture = gl.createTexture()
-    gl.bindTexture(gl.TEXTURE_2D, texture)
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
-    gl.bindTexture(gl.TEXTURE_2D, null)
-    return new Texture(gl, format, texture)
-  }
-
-  /**
-   * Use Texture.create(..) instead.
-   * @param {WebGLRenderingContext}gl
-   * @param {number}format
-   * @param {WebGLTexture}texture
-   * @private
-   */
-  constructor (gl, format, texture) {
-    /**
-     * @type {WebGLRenderingContext}
-     */
-    this.gl = gl
-    /**
-     * @type {WebGLTexture}
-     */
-    this.texture = texture
-    /**
-     * @type {number}
-     */
-    this.format = format
-  }
-
-  /**
-   * @param {!Uint8Array|HTMLVideoElement}buffer
-   * @param {!Rect}geo
-   * @param {number}stride
-   */
-  subImage2dBuffer (buffer, x, y, width, height) {
-    const gl = this.gl
-    gl.bindTexture(gl.TEXTURE_2D, this.texture)
-    gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, width, height, this.format, gl.UNSIGNED_BYTE, buffer)
-    gl.bindTexture(gl.TEXTURE_2D, null)
-  }
-
-  /**
-   * @param {!Uint8Array|HTMLVideoElement}buffer
-   * @param {number}width
-   * @param {number}height
-   */
-  image2dBuffer (buffer, width, height) {
-    const gl = this.gl
-    gl.bindTexture(gl.TEXTURE_2D, this.texture)
-    gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.format, gl.UNSIGNED_BYTE, buffer)
-    gl.bindTexture(gl.TEXTURE_2D, null)
-  }
-
-  delete () {
-    this.gl.deleteTexture(this.texture)
-    this.texture = null
-  }
-}

+ 0 - 131
src/video/YUVSurfaceShader.js

@@ -1,131 +0,0 @@
-import ShaderProgram from './ShaderProgram'
-import ShaderCompiler from './ShaderCompiler'
-import { fragmentYUV, vertexQuad } from './ShaderSources'
-
-export default class YUVSurfaceShader {
-  /**
-   *
-   * @param {WebGLRenderingContext} gl
-   * @returns {YUVSurfaceShader}
-   */
-  static create (gl) {
-    const program = this._initShaders(gl)
-    const shaderArgs = this._initShaderArgs(gl, program)
-    const vertexBuffer = this._initBuffers(gl)
-
-    return new YUVSurfaceShader(gl, vertexBuffer, shaderArgs, program)
-  }
-
-  static _initShaders (gl) {
-    const program = new ShaderProgram(gl)
-    program.attach(ShaderCompiler.compile(gl, vertexQuad))
-    program.attach(ShaderCompiler.compile(gl, fragmentYUV))
-    program.link()
-    program.use()
-
-    return program
-  }
-
-  static _initShaderArgs (gl, program) {
-    // find shader arguments
-    const shaderArgs = {}
-    shaderArgs.yTexture = program.getUniformLocation('yTexture')
-    shaderArgs.uTexture = program.getUniformLocation('uTexture')
-    shaderArgs.vTexture = program.getUniformLocation('vTexture')
-
-    shaderArgs.u_projection = program.getUniformLocation('u_projection')
-
-    shaderArgs.a_position = program.getAttributeLocation('a_position')
-    gl.enableVertexAttribArray(shaderArgs.a_position)
-    shaderArgs.a_texCoord = program.getAttributeLocation('a_texCoord')
-    gl.enableVertexAttribArray(shaderArgs.a_texCoord)
-
-    return shaderArgs
-  }
-
-  static _initBuffers (gl) {
-    // Create vertex buffer object.
-    return gl.createBuffer()
-  }
-
-  constructor (gl, vertexBuffer, shaderArgs, program) {
-    this.gl = gl
-    this.vertexBuffer = vertexBuffer
-    this.shaderArgs = shaderArgs
-    this.program = program
-  }
-
-  /**
-   *
-   * @param {Texture} textureY
-   * @param {Texture} textureU
-   * @param {Texture} textureV
-   */
-  setTexture (textureY, textureU, textureV) {
-    const gl = this.gl
-
-    gl.uniform1i(this.shaderArgs.yTexture, 0)
-    gl.uniform1i(this.shaderArgs.uTexture, 1)
-    gl.uniform1i(this.shaderArgs.vTexture, 2)
-
-    gl.activeTexture(gl.TEXTURE0)
-    gl.bindTexture(gl.TEXTURE_2D, textureY.texture)
-
-    gl.activeTexture(gl.TEXTURE1)
-    gl.bindTexture(gl.TEXTURE_2D, textureU.texture)
-
-    gl.activeTexture(gl.TEXTURE2)
-    gl.bindTexture(gl.TEXTURE_2D, textureV.texture)
-  }
-
-  use () {
-    this.program.use()
-  }
-
-  release () {
-    const gl = this.gl
-    gl.useProgram(null)
-  }
-
-  /**
-   * @param {{w:number, h:number}}encodedFrameSize
-   * @param {{maxXTexCoord:number, maxYTexCoord:number}} h264RenderState
-   */
-  updateShaderData (encodedFrameSize, h264RenderState) {
-    const { w, h } = encodedFrameSize
-    this.gl.viewport(0, 0, w, h)
-    this.program.setUniformM4(this.shaderArgs.u_projection, [
-      2.0 / w, 0, 0, 0,
-      0, 2.0 / -h, 0, 0,
-      0, 0, 1, 0,
-      -1, 1, 0, 1
-    ])
-    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer)
-    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
-      // First triangle
-      // top left:
-      0, 0, 0, 0,
-      // top right:
-      w, 0, h264RenderState.maxXTexCoord, 0,
-      // bottom right:
-      w, h, h264RenderState.maxXTexCoord, h264RenderState.maxYTexCoord,
-
-      // Second triangle
-      // bottom right:
-      w, h, h264RenderState.maxXTexCoord, h264RenderState.maxYTexCoord,
-      // bottom left:
-      0, h, 0, h264RenderState.maxYTexCoord,
-      // top left:
-      0, 0, 0, 0
-    ]), this.gl.DYNAMIC_DRAW)
-    this.gl.vertexAttribPointer(this.shaderArgs.a_position, 2, this.gl.FLOAT, false, 16, 0)
-    this.gl.vertexAttribPointer(this.shaderArgs.a_texCoord, 2, this.gl.FLOAT, false, 16, 8)
-  }
-
-  draw () {
-    const gl = this.gl
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
-    gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 6)
-    gl.bindTexture(gl.TEXTURE_2D, null)
-  }
-}

+ 0 - 3
src/video/h264.worker.js

@@ -1,3 +0,0 @@
-import { init } from 'tinyh264'
-
-init()

+ 0 - 208
src/video/index.js

@@ -1,208 +0,0 @@
-// import H264Worker from "./h264.worker.js";
-import H264Worker from "web-worker:./h264.worker.js";
-import YUVSurfaceShader from "./YUVSurfaceShader";
-import Texture from "./Texture";
-
-// import ChunkLoader from "./chunkLoader.js";
-let tinyH264Worker = null;
-
-let nroFrames = 0;
-let start = 0;
-let videoStreamId = 1;
-let cacheBuffer = [];
-const fetches = [];
-let canvas = null;
-let yuvSurfaceShader = null;
-let yTexture = null;
-let uTexture = null;
-let vTexture = null;
-
-// var Stream = (function stream() {
-//   function constructor(url) {
-//     this.url = url;
-//   }
-
-//   constructor.prototype = {
-//     readAll: function (progress, complete) {
-//       var xhr = new XMLHttpRequest();
-//       var async = true;
-//       xhr.open("GET", this.url, async);
-//       xhr.responseType = "arraybuffer";
-//       if (progress) {
-//         xhr.onprogress = function (event) {
-//           progress(xhr.response, event.loaded, event.total);
-//         };
-//       }
-//       xhr.onreadystatechange = function (event) {
-//         if (xhr.readyState === 4) {
-//           complete(xhr.response);
-
-//           // var byteArray = new Uint8Array(xhr.response);
-//           // var array = Array.prototype.slice.apply(byteArray);
-//           // complete(array);
-//         }
-//       };
-//       xhr.send(null);
-//     },
-//   };
-//   return constructor;
-// })();
-
-/**
- * @param {Uint8Array} h264Nal
- */
-function decode(h264Nal) {
-  tinyH264Worker.postMessage(
-    {
-      type: "decode",
-      data: h264Nal.buffer,
-      offset: h264Nal.byteOffset,
-      length: h264Nal.byteLength,
-      renderStateId: videoStreamId,
-    },
-    [h264Nal.buffer]
-  );
-}
-
-function decodeNext() {
-  const nextFrame = cacheBuffer.shift();
-  // console.log("nextFrame", nextFrame);
-  if (nextFrame != null) {
-    decode(nextFrame);
-  } else {
-    const fps = (1000 / (Date.now() - start)) * nroFrames;
-
-    window.alert(
-      `Decoded ${nroFrames} (${canvas.width} x ${canvas.height} ) frames in ${Date.now() - start}ms @ ${
-        fps >> 0
-      }FPS`
-    );
-  }
-}
-
-// const vid1 = new ChunkLoader({
-//   url: "./video/0_1_0.mp4",
-// });
-
-// console.log("vid1", vid1);
-// vid1.read().then((data) => {
-//   console.log("data", data);
-// });
-
-tinyH264Worker = new H264Worker();
-
-function initWebGLCanvas() {
-  canvas = document.createElement("canvas");
-  canvas.id = "test_canvas";
-  canvas.style = `position: fixed;top:0;left: 0;z-index: 100;`;
-  const gl = canvas.getContext("webgl");
-  yuvSurfaceShader = YUVSurfaceShader.create(gl);
-  yTexture = Texture.create(gl, gl.LUMINANCE);
-  uTexture = Texture.create(gl, gl.LUMINANCE);
-  vTexture = Texture.create(gl, gl.LUMINANCE);
-
-  document.body.append(canvas);
-}
-
-// debugger
-
-tinyH264Worker.addEventListener("message", (e) => {
-  const message =
-    /** @type {{type:string, width:number, height:number, data:ArrayBuffer, renderStateId:number}} */ e.data;
-  console.log("message", message.type);
-  switch (message.type) {
-    case "pictureReady":
-      onPictureReady(message);
-      break;
-    case "decoderReady":
-      initWebGLCanvas();
-      for (let i = 0; i < 300; i++) {
-        // https://laser-data.oss-cn-shenzhen.aliyuncs.com/test-video/earth/
-        fetches.push(
-          fetch(`https://laser-data.oss-cn-shenzhen.aliyuncs.com/test-video/earth/${i}`).then((response) => {
-            return response.arrayBuffer().then(function (buffer) {
-              //h264
-              cacheBuffer[i] = new Uint8Array(buffer);
-            });
-          })
-        );
-      }
-      Promise.all(fetches).then(() => {
-        nroFrames = cacheBuffer.length;
-        start = Date.now();
-        // console.log("nroFrames", nroFrames);
-        decodeNext();
-      });
-
-      break;
-  }
-});
-
-/**
- * @param {{width:number, height:number, data: ArrayBuffer}}message
- */
-function onPictureReady(message) {
-  const { width, height, data } = message;
-  // console.log("onPictureReady", message);
-  onPicture(new Uint8Array(data), width, height);
-}
-
-/**
- * @param {Uint8Array}buffer
- * @param {number}width
- * @param {number}height
- */
-function onPicture(buffer, width, height) {
-  decodeNext();
-
-  canvas.width = width;
-  canvas.height = height;
-
-  // the width & height returned are actually padded, so we have to use the frame size to get the real image dimension
-  // when uploading to texture
-  const stride = width; // stride
-  // height is padded with filler rows
-
-  // if we knew the size of the video before encoding, we could cut out the black filler pixels. We don't, so just set
-  // it to the size after encoding
-  const sourceWidth = width;
-  const sourceHeight = height;
-  const maxXTexCoord = sourceWidth / stride;
-  const maxYTexCoord = sourceHeight / height;
-
-  const lumaSize = stride * height;
-  const chromaSize = lumaSize >> 2;
-
-  const yBuffer = buffer.subarray(0, lumaSize);
-  const uBuffer = buffer.subarray(lumaSize, lumaSize + chromaSize);
-  const vBuffer = buffer.subarray(
-    lumaSize + chromaSize,
-    lumaSize + 2 * chromaSize
-  );
-  console.log('yBuffer',1)
-  window.updateTexture( yBuffer );
-
-  const chromaHeight = height >> 1;
-  const chromaStride = stride >> 1;
-
-  // we upload the entire image, including stride padding & filler rows. The actual visible image will be mapped
-  // from texture coordinates as to crop out stride padding & filler rows using maxXTexCoord and maxYTexCoord.
-
-  yTexture.image2dBuffer(yBuffer, stride, height);
-  uTexture.image2dBuffer(uBuffer, chromaStride, chromaHeight);
-  vTexture.image2dBuffer(vBuffer, chromaStride, chromaHeight);
-
-  yuvSurfaceShader.setTexture(yTexture, uTexture, vTexture);
-  yuvSurfaceShader.updateShaderData(
-    { w: width, h: height },
-    { maxXTexCoord, maxYTexCoord }
-  );
-  // debugger
-    // data = window.changeTexture(data);
-    // window.updateTexture( data );
-   //yuvSurfaceShader.draw();
-}
-
-// steam1.readAll(null, function (buffer) {
-//   console.log("buffer", buffer);
-// });

+ 0 - 72
src/video/test.js

@@ -1,72 +0,0 @@
-import YUVSurfaceShader from "./YUVSurfaceShader";
-import Texture from "./Texture";
-
-let canvas = null;
-let yuvSurfaceShader = null;
-let yTexture = null;
-let uTexture = null;
-let vTexture = null;
-
-function initWebGLCanvas() {
-  canvas = document.createElement("canvas");
-  canvas.id = "test_canvas";
-  canvas.style = `position: fixed;top:0;left: 0;z-index: 100;`;
-  const gl = canvas.getContext("webgl");
-  yuvSurfaceShader = YUVSurfaceShader.create(gl);
-  yTexture = Texture.create(gl, gl.LUMINANCE);
-  uTexture = Texture.create(gl, gl.LUMINANCE);
-  vTexture = Texture.create(gl, gl.LUMINANCE);
-
-  document.body.append(canvas);
-}
-
-function draw(buffer, width, height) {
-  canvas.width = width;
-  canvas.height = height;
-
-  // the width & height returned are actually padded, so we have to use the frame size to get the real image dimension
-  // when uploading to texture
-  const stride = width; // stride
-  // height is padded with filler rows
-
-  // if we knew the size of the video before encoding, we could cut out the black filler pixels. We don't, so just set
-  // it to the size after encoding
-  const sourceWidth = width;
-  const sourceHeight = height;
-  const maxXTexCoord = sourceWidth / stride;
-  const maxYTexCoord = sourceHeight / height;
-
-  const lumaSize = stride * height;
-  const chromaSize = lumaSize >> 2;
-
-  const yBuffer = buffer.subarray(0, lumaSize);
-  const uBuffer = buffer.subarray(lumaSize, lumaSize + chromaSize);
-  const vBuffer = buffer.subarray(
-    lumaSize + chromaSize,
-    lumaSize + 2 * chromaSize
-  );
-//   console.log("yBuffer", 1);
-//   window.updateTexture(yBuffer);
-
-  const chromaHeight = height >> 1;
-  const chromaStride = stride >> 1;
-
-  // we upload the entire image, including stride padding & filler rows. The actual visible image will be mapped
-  // from texture coordinates as to crop out stride padding & filler rows using maxXTexCoord and maxYTexCoord.
-
-  yTexture.image2dBuffer(yBuffer, stride, height);
-  uTexture.image2dBuffer(uBuffer, chromaStride, chromaHeight);
-  vTexture.image2dBuffer(vBuffer, chromaStride, chromaHeight);
-
-  yuvSurfaceShader.setTexture(yTexture, uTexture, vTexture);
-  yuvSurfaceShader.updateShaderData(
-    { w: width, h: height },
-    { maxXTexCoord, maxYTexCoord }
-  );
-  // debugger
-  // data = window.changeTexture(data);
-  // window.updateTexture( data );
-  yuvSurfaceShader.draw();
-}
-
-export { canvas, initWebGLCanvas, draw };

+ 0 - 107
src/开发笔记.txt

@@ -1,107 +0,0 @@
-1. Logger不能用单例模式,里面的module对应的是类的名称
-2. BABYLON源码修改:
-
-        this._onBeforeRegisterBeforeRenderObserver = null,
-        this._onAfterRegisterBeforeRenderObserver = null,
-        this._RTT1Time = new Rr.a,
-        this._onBeforeRTT1Observer = null,
-        this._onAfterRTT1Observer = null,
-        this._registerAfterRenderTime = new Rr.a,
-        this._onBeforeRegisterAfterRenderObserver = null,
-        this._onAfterRegisterAfterRenderObserver = null,
-        
-
-        Object.defineProperty(e.prototype, "registerBeforeTimeCounter", {
-            get: function() {
-                return this._registerBeforeRenderTime
-            },
-            enumerable: !1,
-            configurable: !0
-        }),
-        Object.defineProperty(e.prototype, "getRTT1TimeCounter", {
-            get: function() {
-                return this._RTT1Time
-            },
-            enumerable: !1,
-            configurable: !0
-        }),
-        Object.defineProperty(e.prototype, "registerAfterTimeCounter", {
-            get: function() {
-                return this._registerAfterRenderTime
-            },
-            enumerable: !1,
-            configurable: !0
-        }),
-
-
-		r.onBeforeRunRegisterBeforeRenderObservable = new Observable,
-        r.onAfterRunRegisterBeforeRenderObservable = new Observable,
-        r.onBeforeRunRegisterAfterRenderObservable = new Observable,
-        r.onAfterRunRegisterAfterRenderObservable = new Observable,
-        r.onBeforeRTT1Observable = new Observable,
-        r.onAfterRTT1Observable = new Observable,
-		
-
-
-
-
-
-        this._onBeforeRegisterBeforeRenderObserver = e.onBeforeRunRegisterBeforeRenderObservable.add(function() {
-            t._registerBeforeRenderTime.beginMonitoring()
-        }),
-        this._onAfterRegisterBeforeRenderObserver = e.onAfterRunRegisterBeforeRenderObservable.add(function() {
-            t._registerBeforeRenderTime.endMonitoring()
-        }),
-        this._onBeforeRegisterAfterRenderObserver = e.onBeforeRunRegisterAfterRenderObservable.add(function() {
-            t._registerAfterRenderTime.beginMonitoring()
-        }),
-        this._onAfterRegisterAfterRenderObserver = e.onAfterRunRegisterAfterRenderObservable.add(function() {
-            t._registerAfterRenderTime.endMonitoring()
-        }),
-        this._onBeforeRTT1Observer = e.onBeforeRTT1Observable.add(function() {
-            t._RTT1Time.beginMonitoring()
-        }),
-        this._onAfterRTT1Observer = e.onAfterRTT1Observable.add(function() {
-            t._RTT1Time.endMonitoring()
-        })
-
-
-        this.onBeforeRunRegisterBeforeRenderObservable.notifyObservers(this),
-        this.onBeforeRenderObservable.notifyObservers(this),
-        this.onAfterRunRegisterBeforeRenderObservable.notifyObservers(this),
-
-
-
-
-
-
-
-        this.onBeforeRunRegisterBeforeRenderObservable.clear(),
-        this.onAfterRunRegisterBeforeRenderObservable.clear(),
-        this.onBeforeRTT1Observable.clear(),
-        this.onAfterRTT1Observable.clear(),
-        this.onBeforeRunRegisterAfterRenderObservable.clear(),
-        this.onAfterRunRegisterAfterRenderObservable.clear()
-
-		this.scene.onBeforeRunRegisterBeforeRenderObservable.remove(this._onBeforeRegisterBeforeRenderObserver),
-        this._onBeforeRegisterBeforeRenderObserver = null,
-        this.scene.onAfterRunRegisterBeforeRenderObservable.remove(this._onAfterRegisterBeforeRenderObserver),
-        this._onAfterRegisterBeforeRenderObserver = null,
-        this.scene.onBeforeRunRegisterAfterRenderObservable.remove(this._onBeforeRegisterAfterRenderObserver),
-        this._onBeforeRegisterAfterRenderObserver = null,
-        this.scene.onAfterRunRegisterAfterRenderObservable.remove(this._onAfterRegisterAfterRenderObserver),
-        this._onAfterRegisterAfterRenderObserver = null,
-        this.scene.onBeforeRTT1Observable.remove(this._onBeforeRTT1Observer),
-        this._onBeforeRTT1Observer = null,
-        this.scene.onAfterRTT1Observable.remove(this._onAfterRTT1Observer),
-        this._onAfterRTT1Observer = null,
-		
-		
-/***************************************************************************************************************************************************************************************/
-3. Broadcast类, constructor(xverseRoom, t) 中参数t的意思?
-4. 对方网页端可以录制视频,直接采用了腾讯云oss的sdk,直接上传。代码在这一块:COS$1 = function(i)
-5. EngineProxy里,skinId如果是10048
-
-
-
-

+ 0 - 0
src/接口数据.txt


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff