Browse Source

Merge branch 'newWebRtc' of http://192.168.0.115:3000/xushiting/Metaverse into myrtc

# Conflicts:
#	src/Workers.js
#	src/XMaterialComponent.js
#	src/XSceneManager.js
#	src/Xverse_Room.js
#	src/main.js
zhouenguang 3 years ago
parent
commit
1d8123210c
18 changed files with 1858 additions and 1851 deletions
  1. 350 292
      src/ActionsHandler.js
  2. 17 17
      src/Broadcast.js
  3. 71 84
      src/EventsManager.js
  4. 18 20
      src/JoyStick.js
  5. 10 10
      src/ModelManager.js
  6. 39 28
      src/Signal.js
  7. 138 139
      src/XAnimationController.js
  8. 296 189
      src/XAvatar.js
  9. 103 88
      src/XAvatarComopnent.js
  10. 264 229
      src/XAvatarLoader.js
  11. 92 103
      src/XAvatarManager.js
  12. 0 222
      src/XSequence.js
  13. 190 145
      src/XverseAvatar.js
  14. 226 191
      src/XverseAvatarManager.js
  15. 0 91
      src/XverseEffect.js
  16. 37 1
      src/enum/Actions.js
  17. 5 0
      src/enum/QueueType.js
  18. 2 2
      src/main.js

+ 350 - 292
src/ActionsHandler.js

@@ -4,44 +4,46 @@ import util from "./util.js"
 import Person from "./enum/Person.js"
 import ClickType from "./enum/ClickType.js"
 import Logger from "./Logger.js"
+import MessageHandleType from "./enum/MessageHandleType.js"
 
 const logger = new Logger('actions-handler')
 const QueueActions = [Actions.Transfer, Actions.ChangeSkin, Actions.GetOnVehicle, Actions.GetOffVehicle];
+
 export default class ActionsHandler {
-    constructor(e) {
+    constructor(room) {
         this.currentActiveAction = null
-        this.room = e
+        this.room = room
     }
 
-    async avatarComponentsSync(e){
-        const t = {
-            action_type: Actions.SetPlayerState,
-            set_player_state_action: {
-                player_state: {
-                    avatar_components: JSON.stringify(e)
+    async avatarComponentsSync(avatarComponents) {
+        this.sendData({
+            data: {
+                action_type: Actions.SetPlayerState,
+                set_player_state_action: {
+                    player_state: {
+                        avatar_components: JSON.stringify(avatarComponents)
+                    }
                 }
             }
-        };
-        this.sendData({
-            data: t
         })
     }
 
-    async sendData(actionData) {
-
-        console.log('发送数据:'+JSON.stringify(actionData))
+    async sendData(actionData) 
+    {
+        // console.error("[Action]", Actions[actionData.data.action_type])
 
         await this.beforeSend(actionData);
         const traceId = util.uuid();
+        // 向后端发送action_type信息,获取signal和stream
         this.room.networkController.sendRtcData(le(oe({}, actionData.data), {
             trace_id: traceId,
             user_id: this.room.options.userId
         }));
 
-        if (actionData.track === !1)
-        {
+        if (actionData.track === !1) {
             return Promise.resolve(null);
         }
+        
         const { sampleRate=1, timeout=2e3, tag, data, special } = actionData;
         return eventsManager.track({
             timeout,
@@ -58,7 +60,8 @@ export default class ActionsHandler {
         })
     }
 
-    async beforeSend(e) {
+    async beforeSend(e) 
+    {
         var o;
         const t = (o = this.room._userAvatar) == null ? void 0 : o.isMoving
           , r = e.data.action_type;
@@ -76,182 +79,211 @@ export default class ActionsHandler {
                 logger.error("before action stopMoving failed", a)
             }
     }
-    async moveTo(e) {
-        const {point: t, extra: r="", motionType: n} = e
-          , o = {
-            action_type: Actions.Clicking,
-            clicking_action: {
-                clicking_point: t,
-                clicking_type: ClickType.IgnoreView,
-                extra: encodeURIComponent(r),
-                attitude: n
-            },
-            clicking_state: this.room._currentClickingState
-        };
+
+    // 点击行走至某一点时执行
+    async moveTo({point, extra="", motionType}) 
+    {
         return this.sendData({
-            data: o
+            data: {
+                action_type: Actions.Clicking,
+                clicking_action: {
+                    clicking_point: point,
+                    clicking_type: ClickType.IgnoreView,
+                    extra: encodeURIComponent(extra),
+                    attitude: motionType
+                },
+                clicking_state: this.room._currentClickingState
+            }
         })
     }
-    transfer(e) {
-        const {renderType: t, player: r, camera: n, areaName: o, attitude: a, pathName: s, person: l, noMedia: u, timeout: c, tag: h, special: f} = e
-          , d = {
+
+    transfer({renderType, player, camera, areaName, attitude, pathName, person:personType, noMedia, timeout, tag, special}) 
+    {
+        return this.sendData({
             data: {
                 action_type: Actions.Transfer,
                 transfer_action: {
-                    render_type: t,
-                    player: r,
-                    camera: n,
-                    areaName: o,
-                    attitude: a,
-                    pathName: s,
+                    render_type: renderType,
+                    player,
+                    camera,
+                    areaName,
+                    attitude,
+                    pathName,
                     person: {
-                        type: l
+                        type: personType
                     },
-                    noMedia: u,
+                    noMedia,
                     tiles: [0, 1, 2, 4]
                 }
             },
-            special: f,
-            timeout: c || 4e3,
-            tag: h
-        };
-        return this.sendData(d).then(_=>(typeof l != "undefined" && this.room.updateCurrentNetworkOptions({
-            person: l,
-            rotationRenderType: t
-        }),
-        _))
-    }
-    changeRotationRenderType(e) {
-        const {renderType: t, player: r, camera: n, areaName: o, attitude: a, pathName: s} = e;
+            special,
+            timeout: timeout || 4e3,
+            tag
+        }).then(_ => (
+            typeof personType != "undefined" && this.room.updateCurrentNetworkOptions({
+                person: personType,
+                rotationRenderType: renderType
+            }),
+            _
+        ))
+    }
+
+    // Panorama.exit()中调用
+    changeRotationRenderType({renderType, player, camera, areaName, attitude, pathName}) 
+    {
         return this.transfer({
-            renderType: t,
-            player: r,
-            camera: n,
-            areaName: o,
-            attitude: a,
-            pathName: s,
+            renderType,
+            player,
+            camera,
+            areaName,
+            attitude,
+            pathName,
             tag: "changeToRotationVideo"
         })
     }
-    requestPanorama(e, noMedia, timeout) {
-        const {camera: camera, player: player, areaName: areaName, attitude: attitude, pathName: pathName, tag: tag} = e;
+
+    // 用于请求第一人称视角下的pano数据
+    requestPanorama({camera, player, areaName, attitude, pathName, tag}, noMedia, timeout) 
+    {
         return this.transfer({
             renderType: RenderType.ClientRotationPano,
-            player: player,
-            camera: camera,
+            player,
+            camera,
             person: Person.First,
-            areaName: areaName,
-            attitude: attitude,
-            pathName: pathName,
+            areaName,
+            attitude,
+            pathName,
             noMedia: noMedia,
             timeout: timeout,
             tag: tag || "requestPanorama",
             special: !noMedia
         })
     }
-    setMotionType(e) {
+
+    // 设置角色行动类型,如MotionType.Walk。方法未调用
+    setMotionType(type) 
+    {
         return this.transfer({
-            attitude: e,
+            attitude: type,
             tag: "setMotionType"
         })
     }
-    setNickName(e) {
-        const t = {
-            action_type: Actions.ChangeNickname,
-            change_nickname_action: {
-                nickname: e
-            }
-        };
+
+    // 设置角色昵称
+    setNickName(nickname) 
+    {
         return this.sendData({
-            data: t
+            data: {
+                action_type: Actions.ChangeNickname,
+                change_nickname_action: {
+                    nickname
+                }
+            }
         })
     }
-    getReserveSeat({routeId: e, name: t}) {
-        const r = {
-            action_type: Actions.ReserveSeat,
-            reserve_seat_action: {
-                route_id: e,
-                name: t
-            }
-        };
+
+    // 方法未调用
+    getReserveSeat({routeId, name}) 
+    {
         return this.sendData({
-            data: r
+            data: {
+                action_type: Actions.ReserveSeat,
+                reserve_seat_action: {
+                    route_id: routeId,
+                    name
+                }
+            }
         })
     }
-    getReserveStatus({routeId: e, name: t, need_detail: r}) {
-        const n = {
-            action_type: Actions.GetReserveStatus,
-            get_reserve_status_action: {
-                route_id: e,
-                name: t,
-                need_detail: r
-            }
-        };
+
+    // 方法未调用
+    getReserveStatus({routeId, name, need_detail}) 
+    {
         return this.sendData({
-            data: n,
+            data: {
+                action_type: Actions.GetReserveStatus,
+                get_reserve_status_action: {
+                    route_id: routeId,
+                    name,
+                    need_detail
+                }
+            },
             timeout: 2e3
         }).then(o=>o.reserveDetail)
     }
-    stopMoving() {
-        const e = {
-            action_type: Actions.StopMoving,
-            stop_move_action: {}
-        };
+
+    // 停止移动。在playAnimation时调用
+    stopMoving() 
+    {
         return this.sendData({
-            data: e
+            data: {
+                action_type: Actions.StopMoving,
+                stop_move_action: {}
+            }
         })
     }
-    getOnVehicle({routeId: e, name: t, camera: r}) {
-        const n = {
-            action_type: Actions.GetOnVehicle,
-            get_on_vehicle_action: {
-                route_id: e,
-                name: t,
-                camera: r
-            }
-        };
+
+    // 方法未调用
+    getOnVehicle({routeId, name, camera}) 
+    {
         return this.sendData({
-            data: n
+            data: {
+                action_type: Actions.GetOnVehicle,
+                get_on_vehicle_action: {
+                    route_id: routeId,
+                    name,
+                    camera
+                }
+            }
         })
     }
-    getOffVehicle({renderType: e, player: t, camera: r}) {
-        const n = {
-            action_type: Actions.GetOffVehicle,
-            get_off_vehicle_action: {
-                render_type: e,
-                player: t,
-                camera: r
-            }
-        };
+
+    // 方法未调用
+    getOffVehicle({renderType, player, camera}) 
+    {
         return this.sendData({
-            data: n
+            data: {
+                action_type: Actions.GetOffVehicle,
+                get_off_vehicle_action: {
+                    render_type: renderType,
+                    player,
+                    camera
+                }
+            }
         })
     }
-    confirmEvent(e) {
-        const t = {
-            action_type: Actions.ConfirmEvent,
-            confirm_event_action: {
-                id: e
-            }
-        };
+
+    // 在_handleAvatar时调用
+    confirmEvent(id) 
+    {
         return this.sendData({
-            data: t,
+            data: {
+                action_type: Actions.ConfirmEvent,
+                confirm_event_action: {
+                    id
+                }
+            },
             track: !1
         })
     }
-    echo(e) {
-        const t = {
-            action_type: Actions.Echo,
-            echo_msg: {
-                echoMsg: e
-            }
-        };
+
+    // 心跳
+    echo(echoMsg) 
+    {
         return this.sendData({
-            data: t,
+            data: {
+                action_type: Actions.Echo,
+                echo_msg: {
+                    echoMsg
+                }
+            },
             track: !1
         })
     }
-    async changeSkin(e) {
+
+    // 方法未调用
+    async changeSkin(e) 
+    {
         const t = e.special === void 0 ? e.renderType === RenderType.ClientRotationPano : e.special
           , {skinId: r, mode: n, landingType: o=LandingType.Stay, landingPoint: a, landingCamera: s, renderType: l, areaName: u, attitude: c, pathName: h, person: f, noMedia: d, timeout: _, roomTypeId: g=""} = e
           , m = this.room.skinList.filter(y=>y.id === r)[0];
@@ -294,7 +326,9 @@ export default class ActionsHandler {
         }
         ).catch(y=>d ? this.handleChangeSkin(e) : Promise.reject(y))
     }
-    handleChangeSkin(e) {
+
+    handleChangeSkin(e) 
+    {
         const {skinId: t, mode: r, renderType: n, areaName: o, attitude: a, pathName: s} = e;
         return this.room.sceneManager.staticmeshComponent.getCgMesh().show(),
         this.room.sceneManager.cameraComponent.switchToCgCamera(),
@@ -319,205 +353,229 @@ export default class ActionsHandler {
         }
         )
     }
-    rotate({pitch: e, yaw: t}) {
-        var n;
-        if (this.room.disableRotate || this.room.isPano || ((n = this.room._userAvatar) == null ? void 0 : n._isChangingComponentsMode))
-            return;
-        const r = {
-            action_type: Actions.Rotation,
-            rotation_action: {
-                vertical_move: e,
-                horizontal_move: -t
-            }
-        };
+
+    // 相机旋转
+    rotate({pitch, yaw}) 
+    {
+        if (
+            this.room.disableRotate || 
+            this.room.isPano || 
+            (this.room._userAvatar == null ? void 0 : this.room._userAvatar._isChangingComponentsMode)
+        ) return;
+        
         this.sendData({
-            data: r,
+            data: {
+                action_type: Actions.Rotation,
+                rotation_action: {
+                    vertical_move: pitch,
+                    horizontal_move: -yaw
+                }
+            },
             sampleRate: .02
         })
     }
-    turnTo(e) {
-        const {point: t, timeout: r=2e3, offset: n=8} = e || {}
-          , o = {
-            action_type: Actions.TurnTo,
-            turn_to_action: {
-                turn_to_point: t,
-                offset: n
-            }
-        };
+
+    // 方法未调用
+    turnTo({point, timeout=2e3, offset=8} = {}) 
+    {
         return this.sendData({
-            data: o,
-            timeout: r
+            data: {
+                action_type: Actions.TurnTo,
+                turn_to_action: {
+                    turn_to_point: point,
+                    offset
+                }
+            },
+            timeout
         })
     }
-    rotateTo(e) {
-        const {point: t, offset: r=0, speed: n=3} = e || {}
-          , o = {
-            action_type: Actions.RotateTo,
-            rotate_to_action: {
-                rotate_to_point: t,
-                offset: r,
-                speed: n
-            }
-        };
+
+    // 人物旋转
+    rotateTo({point, offset=0, speed=3} = {}) 
+    {
         return this.sendData({
-            data: o
+            data: {
+                action_type: Actions.RotateTo,
+                rotate_to_action: {
+                    rotate_to_point: point,
+                    offset,
+                    speed
+                }
+            }
         })
     }
-    broadcast(e) {
-        const {data: t, msgType: r=MessageHandleType.MHT_FollowListMulticast, targetUserIds: n} = e;
-        if (r === MessageHandleType.MHT_CustomTargetSync && !Array.isArray(n))
-            return Promise.reject(new ParamError(`param targetUserIds is required  when msgType is ${MessageHandleType[r]}`));
-        const o = {
+
+    broadcast({data, msgType=MessageHandleType.MHT_FollowListMulticast, targetUserIds}) 
+    {
+        if (msgType === MessageHandleType.MHT_CustomTargetSync && !Array.isArray(targetUserIds))
+            return Promise.reject(new ParamError(`param targetUserIds is required  when msgType is ${MessageHandleType[msgType]}`));
+
+        let sendData = {
             action_type: Actions.Broadcast,
             broadcast_action: {
-                data: JSON.stringify(t),
+                data: JSON.stringify(data),
                 user_id: this.room.options.userId,
-                msgType: r
+                msgType
             }
-        };
-        return Array.isArray(n) && r === MessageHandleType.MHT_CustomTargetSync && (o.broadcast_action.target_user_ids = n),
-        this.room.actionsHandler.sendData({
-            data: o,
-            tag: t.broadcastType
+        }
+        if (msgType === MessageHandleType.MHT_CustomTargetSync && Array.isArray(targetUserIds)) {
+            sendData.broadcast_action.target_user_ids = targetUserIds
+        }
+
+        return this.room.actionsHandler.sendData({
+            data: sendData,
+            tag: data.broadcastType
         })
     }
-    getNeighborPoints(e) {
-        const {point: t, containSelf: r=!1, searchRange: n=500} = e
-          , o = {
-            action_type: Actions.GetNeighborPoints,
-            get_neighbor_points_action: {
-                point: t,
-                level: 1,
-                containSelf: r,
-                searchRange: n
-            }
-        };
+
+    // 用于Debug.getPointsAndRender()
+    getNeighborPoints({point, containSelf=!1, searchRange=500}) 
+    {
         return this.sendData({
-            data: o
+            data: {
+                action_type: Actions.GetNeighborPoints,
+                get_neighbor_points_action: {
+                    point,
+                    level: 1,
+                    containSelf,
+                    searchRange
+                }
+            }
         }).then(a=>a.nps)
     }
-    playCG(e) {
-        const t = {
-            action_type: Actions.PlayCG,
-            play_cg_action: {
-                cg_name: e
-            }
-        };
+
+    // 方法未调用
+    playCG(cgName) 
+    {
         return this.sendData({
-            data: t
+            data: {
+                action_type: Actions.PlayCG,
+                play_cg_action: {
+                    cg_name: cgName
+                }
+            }
         })
     }
-    audienceToVisitor(e) {
-        const {avatarId: t, avatarComponents: r, player: n, camera: o} = e
-          , a = {
-            action_type: Actions.AudienceChangeToVisitor,
-            audienceChangeToVisitorAction: {
-                avatarID: t,
-                avatarComponents: r,
-                player: n,
-                camera: o
-            }
-        };
+
+    // 方法未调用
+    audienceToVisitor({avatarId, avatarComponents, player, camera}) 
+    {
         return logger.debug("send data: audience to visitor"),
         this.sendData({
-            data: a
-        })
-    }
-    visitorToAudience(e) {
-        const {renderType: t, player: r, camera: n, areaName: o, attitude: a, pathName: s, person: l, noMedia: u} = e
-          , c = {
-            action_type: Actions.VisitorChangeToAudience,
-            visitorChangeToAudienceAction: {
-                transferAction: {
-                    render_type: t,
-                    player: r,
-                    camera: n,
-                    areaName: o,
-                    attitude: a,
-                    pathName: s,
-                    person: {
-                        type: l
-                    },
-                    noMedia: u,
-                    tiles: [0, 1, 2, 4]
+            data: {
+                action_type: Actions.AudienceChangeToVisitor,
+                audienceChangeToVisitorAction: {
+                    avatarID: avatarId,
+                    avatarComponents,
+                    player,
+                    camera
                 }
             }
-        };
+        })
+    }
+
+    // 方法未调用
+    visitorToAudience({renderType, player, camera, areaName, attitude, pathName, person:personType, noMedia}) 
+    {
         return logger.debug("send data: visitor to audience"),
         this.sendData({
-            data: c
+            data: {
+                action_type: Actions.VisitorChangeToAudience,
+                visitorChangeToAudienceAction: {
+                    transferAction: {
+                        render_type: renderType,
+                        player,
+                        camera,
+                        areaName,
+                        attitude,
+                        pathName,
+                        person: {
+                            type: personType
+                        },
+                        noMedia,
+                        tiles: [0, 1, 2, 4]
+                    }
+                }
+            }
         })
     }
-    removeVisitor(e) {
-        const {removeType: t, userIDList: r, extraInfo: n=""} = e
-          , o = {
-            action_type: Actions.RemoveVisitor,
-            removeVisitorAction: {
-                removeVisitorEvent: t,
-                userIDList: r,
-                extraInfo: encodeURIComponent(n)
-            }
-        };
+
+    // 方法未调用
+    removeVisitor({removeType, userIDList, extraInfo=""}) 
+    {
         return logger.debug("send data: remove visitor"),
         this.sendData({
-            data: o
+            data: {
+                action_type: Actions.RemoveVisitor,
+                removeVisitorAction: {
+                    removeVisitorEvent: removeType,
+                    userIDList,
+                    extraInfo: encodeURIComponent(extraInfo)
+                }
+            }
         })
     }
-    getUserWithAvatar(e, t) {
-        const r = {
-            action_type: Actions.GetUserWithAvatar,
-            getUserWithAvatarAction: {
-                userType: e,
-                roomID: t
-            }
-        };
+
+    // 方法未调用
+    getUserWithAvatar(userType, roomID) 
+    {
         return logger.debug("send data: get user with avatar"),
         this.sendData({
-            data: r
+            data: {
+                action_type: Actions.GetUserWithAvatar,
+                getUserWithAvatarAction: {
+                    userType,
+                    roomID
+                }
+            }
         }).then(n=>n.userWithAvatarList)
     }
-    getNewUserState(e) {
-        const i = {
-            action_type: Actions.GetNewUserState,
-            getNewUserStateAction: {
-                userType: e
-            }
-        };
+
+    // 每2秒获取一次新数据。在Xverse_Room.afterJoinRoom()中调用
+    getNewUserState(userType) 
+    {
         return this.sendData({
-            data: i,
+            data: {
+                action_type: Actions.GetNewUserState,
+                getNewUserStateAction: {
+                    userType
+                }
+            },
             sampleRate: 0
         }).then(o => o)
     }
-    setSyncPolicy({
-        syncPolicy: e
-    }) {
-        const i = {
-            action_type: Actions.SetSyncPolicy,
-            setSyncPolicyAction: {
-                syncPolicy: e
-            }
-        };
+
+    // 方法未调用
+    setSyncPolicy({syncPolicy}) 
+    {
         return this.sendData({
-            data: i
+            data: {
+                action_type: Actions.SetSyncPolicy,
+                setSyncPolicyAction: {
+                    syncPolicy
+                }
+            }
         })
     }
-    joystick(e) {
-        const {degree: t, level: r=1} = e
-          , n = util.uuid();
-        let o = -t + 90 + 360;
-        o >= 360 && (o -= 360);
-        const a = {
-            action_type: Actions.Joystick,
-            dir_action: {
-                move_angle: o,
-                speed_level: r
-            },
-            trace_id: n,
-            user_id: this.room.options.userId,
-            packet_id: n
-        };
+
+    // 拖动手柄
+    joystick({degree, level=1}) 
+    {
+        const uuid = util.uuid();
+        let angle = -degree + 90 + 360;
+        angle >= 360 && (angle -= 360);
+
         return this.sendData({
-            data: a,
+            data: {
+                action_type: Actions.Joystick,
+                dir_action: {
+                    move_angle: angle,
+                    speed_level: level
+                },
+                trace_id: uuid,
+                user_id: this.room.options.userId,
+                packet_id: uuid
+            },
             track: !1
         })
     }

+ 17 - 17
src/Broadcast.js

@@ -14,22 +14,22 @@ export default class Broadcast{
         this.handlers.push(t)
     }
 
-    // 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;
-    //     return this.room.actionsHandler.broadcast({
-    //         data: t,
-    //         msgType: r,
-    //         targetUserIds: n
-    //     })
-    // }
+    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;
+        return this.room.actionsHandler.broadcast({
+            data: t,
+            msgType: r,
+            targetUserIds: n
+        })
+    }
 }
 ;

+ 71 - 84
src/EventsManager.js

@@ -10,100 +10,87 @@ export default class EventsManager extends EventEmitter {
         E(this, "events", new Map);
         E(this, "specialEvents", new Map)
     }
-    remove(e, t, r, n) {
-        if (this.specialEvents.has(e) && !n && t === Codes.Success)
-            return;
-        this.events.get(e) && (this.emit(e, {
-            code: t,
-            data: r
-        }),
-        this.events.delete(e),
-        this.specialEvents.delete(e))
+
+    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)
+        )
     }
-    async track(e, t) {
-        const r = e.traceId;
+
+    async track(e, t) 
+    {
+        const traceId = e.traceId;
+
         this.emitTraceIdToDecoder(e);
-        const {sampleRate: n, noReport: o=!1, special: a} = t || {};
-        if (n && Math.random() > n)
-            return Promise.resolve();
+
+        const { sampleRate, noReport=!1, special } = t || {};
+        if (sampleRate && Math.random() > sampleRate) return Promise.resolve();
         const s = Actions[e.event] + "Action"
-          , l = e.tag;
-        this.events.set(r, !0),
-        a && this.specialEvents.set(r, !0);
-        const u = Date.now();
+        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((h,f)=>{
-            if (o)
-                return this.off(r),
-                this.events.delete(r),
-                h(void 0);
-            this.on(r, ({code: _, data: g, msg: m})=>{
-                if (_ === Codes.Success)
-                    h(g),
-                    this.off(r),
-                    logger.infoAndReportMeasurement({
-                        metric: s,
-                        tag: l,
-                        extra: e.extra,
-                        startTime: u,
-                        traceId: r
-                    });
+        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({ metric: s, tag, extra: e.extra, startTime, traceId });
                 else {
-                    if (_ === Codes.ActionMaybeDelay)
-                        return;
-                    if (_ === Codes.DoActionBlocked && e.event === Actions.Rotation) {
-                        logger.debug(s + " response code: " + _);
+                    if (code === Codes.ActionMaybeDelay) return;
+                    if (code === Codes.DoActionBlocked && e.event === Actions.Rotation) {
+                        logger.debug(s + " response code: " + code);
                         return
                     }
-                    const v = util.getErrorByCode(_)
-                      , y = new v(m);
-                    this.off(r),
-                    f(y),
-                    this.emit("actionResponseError", {
-                        error: y,
-                        event: e,
-                        tag: l
-                    }),
-                    logger.infoAndReportMeasurement({
-                        metric: s,
-                        tag: l,
-                        extra: e.extra,
-                        error: y,
-                        startTime: u,
-                        traceId: r
-                    })
+                    const CodeError = util.getErrorByCode(code)
+                      , error = new CodeError(msg);
+                    this.off(traceId),
+                    reject(error),
+                    this.emit("actionResponseError", { error, event: e, tag }),
+                    logger.infoAndReportMeasurement({ metric: s, tag, extra: e.extra, error, startTime, traceId })
                 }
-            }
-            );
-            const d = e.timeout || 2e3;
-            c = window.setTimeout(()=>{
-                if (c && clearTimeout(c),
-                !this.events.get(r))
-                    return;
-                const _ = new ActionResponseTimeoutError(`${s} timeout in ${d}ms`);
-                this.emit("actionResponseTimeout", {
-                    error: _,
-                    event: e,
-                    tag: l
-                }),
-                f(_),
-                this.events.delete(r),
-                this.off(r),
-                logger.infoAndReportMeasurement({
-                    metric: s,
-                    tag: l,
-                    extra: e.extra,
-                    error: _,
-                    startTime: u,
-                    traceId: r
-                })
-            }
-            , d)
-        }
-        )
+            });
+
+            // 超时报错
+            const time = e.timeout || 2e3;
+            c = window.setTimeout(() => 
+            {
+                if (c && clearTimeout(c), !this.events.get(traceId)) return;
+
+                const error = new ActionResponseTimeoutError(`${s} timeout in ${d}ms`);
+                this.emit("actionResponseTimeout", { error, event: e, tag }),
+                reject(error),
+                this.events.delete(traceId),
+                this.off(traceId),
+                logger.infoAndReportMeasurement({ metric: s, tag, extra: e.extra, error, startTime, traceId })
+            }, time)
+        })
     }
+
     emitTraceIdToDecoder(e) {
-        if (e.event === Actions.Rotation || e.event === Actions.Clicking || e.event === Actions.GetOnVehicle || e.event === Actions.GetOffVehicle) {
+        if (
+            e.event === Actions.Rotation || 
+            e.event === Actions.Clicking || 
+            e.event === Actions.GetOnVehicle || 
+            e.event === Actions.GetOffVehicle
+        ) {
             const t = {
                 [Actions.Rotation]: "Rotation",
                 [Actions.GetOnVehicle]: "GetOnVehicle",

+ 18 - 20
src/JoyStick.js

@@ -5,23 +5,22 @@ export default class JoyStick {
         this._room = e
     }
     init(e) {
-        const {interval: t=33, triggerDistance: r=25, style: n={
-            left: 0,
-            bottom: 0
-        }} = e
-          , o = (u,c)=>{
+        const { interval=33, triggerDistance=25, style={left:0, bottom:0} } = e
+
+        const moveFunc = (u,c)=>{
             this._room.actionsHandler.joystick({
                 degree: Math.floor(u),
                 level: Math.floor(c / 5)
             })
         }
-          , a = this._zone;
+        const a = this._zone;
+
         document.body.appendChild(a),
         a.style.position = "absolute",
-        a.style.width = "200px",
-        a.style.height = "200px",
-        a.style.left = String(n.left),
-        a.style.bottom = String(n.bottom),
+        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",
@@ -34,24 +33,23 @@ export default class JoyStick {
             },
             color: "white"
         });
+
         let s, l;
-        return this._joystick.on("move", (u,c)=>{
+        this._joystick.on("move", (u,c)=>{
             s = c
-        }
-        ),
+        })
         this._joystick.on("start", ()=>{
             l = window.setInterval(()=>{
-                s && s.distance > r && o && o(s.angle.degree, s.distance)
+                s && s.distance > triggerDistance && moveFunc && moveFunc(s.angle.degree, s.distance)
             }
-            , t)
-        }
-        ),
+            , interval)
+        })
         this._joystick.on("end", ()=>{
             l && window.clearInterval(l),
             l = void 0
-        }
-        ),
-        this._joystick
+        })
+
+        return this._joystick
     }
     show() {
         if (!this._joystick)

+ 10 - 10
src/ModelManager.js

@@ -26,24 +26,24 @@ export default class ModelManager{
         const n = e.filter(o=>o.typeName === t && o.className === r)[0];
         return n || null
     }
-    async findSkinConfig(e) {
+    async findSkinConfig(skinId) {
         let t = null;
-        if (t = (this.skinList = await this.getSkinsList()).find(n=>n.id === e),
+        if (t = (this.skinList = await this.getSkinsList()).find(n=>n.id === skinId),
         t)
             return t;
         {
-            const n = `skin is invalid: skinId: ${e}`;
+            const n = `skin is invalid: skinId: ${skinId}`;
             return Promise.reject(new ParamError(n))
         }
     }
-    async findRoute(e, t) {
-        const n = (await this.findSkinConfig(e)).routeList.find(o=>o.pathName === t);
-        if (!n) {
-            const o = `find path failed: skinId: ${e}, pathName: ${t}`;
-            return Promise.reject(new ParamError(o))
+    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))
         }
-        return logger.debug("find route success", n),
-        n
+        return logger.debug("find route success", route),
+        route
     }
     async findAssetList(e) {
         const r = (await this.findSkinConfig(e)).assetList;

+ 39 - 28
src/Signal.js

@@ -38,16 +38,18 @@ export default class Signal {
         }
     }
     
-    handleSignal(updateData, i) {
+    handleSignal(data, reject) {
         if (!this.signalHandleActived) return;
-        const time1 = Date.now()
-        const { signal, alreadyUpdateYUV } = updateData;
 
+        const time1 = Date.now()
+        const { signal, alreadyUpdateYUV } = data;
         this.handleActionResponses(signal), this._room.handleSignalHook(signal);
-        const time2 = Date.now();
 
-        if (this.handleSignalPartialArray2.add(time2 - time1), !alreadyUpdateYUV) 
+        const time2 = Date.now();
+        this.handleSignalPartialArray2.add(time2 - time1);
+        if (!alreadyUpdateYUV) 
         {
+            // 断流时,人物停止移动
             const mainUserState = signal.newUserStates && signal.newUserStates.find(state => state.userId === this._room.userId);
             if ((mainUserState && mainUserState.renderInfo) && (this._room._userAvatar && this._room._userAvatar.isMoving)) 
             {
@@ -62,6 +64,7 @@ export default class Signal {
             return
         }
 
+        // 数据过滤
         this.isUpdatedYUV = alreadyUpdateYUV;
         if (!signal) {
             logger.warn("metadata signal is empty");
@@ -75,28 +78,31 @@ export default class Signal {
             this._room.handleRepetLogin();
             return
         }
-
         if (
             signal.code !== void 0 && 
             signal.code !== Codes.Success && 
             signal.code !== Codes.ActionMaybeDelay && 
             signal.code !== Codes.DoActionBlocked && 
             signal.code !== Codes.GetOnVehicle
-        )
-            if (signal.code === Codes.UnReachable) 
-                logger.debug("signal errcode: ", signal.code), this._room.proxyEvents("unreachable");
-            else {
+        ) {
+            if (signal.code === Codes.UnReachable) {
+                logger.debug("signal errcode: ", signal.code);
+                this._room.proxyEvents("unreachable");
+            } else {
                 if (!this._room.joined) {
-                    const nt = getErrorByCode(signal.code),
-                        ot = new nt(signal.msg);
-                    i(ot)
+                    const CodeError = getErrorByCode(signal.code),
+                        error = new CodeError(signal.msg);
+                    reject(error)
                 }
-                logger.error("signal errcode: ", signal), this._room.emit("error", signal)
+                logger.error("signal errcode: ", signal);
+                this._room.emit("error", signal);
             } 
+        }
         
         const time3 = Date.now();
         this.handleSignalPartialArray3.add(time3 - time2);
         const mainUserState = signal.newUserStates && signal.newUserStates.find(state => state.userId === this._room.userId);
+        // Broadcast相关 暂时用不到
         if (signal.broadcastAction) try {
             const nt = JSON.parse(signal.broadcastAction.data);
             Broadcast.handlers.forEach(ot => ot(nt))
@@ -105,11 +111,13 @@ export default class Signal {
         }
 
         const time4 = Date.now();
-        this.handleSignalPartialArray4.add(time4 - time3), 
+        this.handleSignalPartialArray4.add(time4 - time3);
+        // 更新人物数据
         signal.newUserStates && signal.newUserStates.length > 0 && this._room.avatarManager.handleAvatar(signal);
 
         const time5 = Date.now();
-        if (this.handleSignalPartialArray5.add(time5 - time4), mainUserState != null && mainUserState.playerState) {
+        this.handleSignalPartialArray5.add(time5 - time4);
+        if (mainUserState != null && mainUserState.playerState) {
             this._room._currentClickingState = mainUserState.playerState;
             const { pathName, attitude, areaName, skinId } = mainUserState.playerState;
             if (
@@ -123,27 +131,30 @@ export default class Signal {
                 this._room.pathManager.currentAttitude = attitude, 
                 this._room._userAvatar && (this._room._userAvatar.motionType = attitude)
             }
-            this._room.sceneManager.getCurrentShaderMode() !== ECurrentShaderMode.pano && 
-            !this._room.isPano && 
-            mainUserState.playerState.camera && 
-            !this._room.panorama.isLoading && 
-            this._room.camera.setCameraPose(mainUserState.playerState.camera)
+            // 更新相机数据
+            this._room.sceneManager.getCurrentShaderMode() !== ECurrentShaderMode.pano 
+            && !this._room.isPano 
+            && mainUserState.playerState.camera 
+            && !this._room.panorama.isLoading 
+            && this._room.camera.setCameraPose(mainUserState.playerState.camera)
         }
         mainUserState != null && mainUserState.renderInfo && this._room.camera.handleRenderInfo(mainUserState);
 
         const time6 = Date.now();
-        if (this.handleSignalPartialArray6.add(time6 - time5), signal.actionType !== void 0) {
+        this.handleSignalPartialArray6.add(time6 - time5);
+        if (signal.actionType !== void 0) {
             const { actionType, code, echoMsg, traceId } = signal;
-            actionType === Actions.Echo && 
-            code === Codes.Success && 
-            this._room.networkController.rtcp.heartbeat.pong(echoMsg, traceId), 
-            code !== Codes.Success ? eventsManager.remove(traceId, code) : [
+            // 移除暂存的traceId
+            actionType === Actions.Echo 
+            && code === Codes.Success 
+            && this._room.networkController.rtcp.heartbeat.pong(echoMsg, traceId)
+            , code !== Codes.Success ? eventsManager.remove(traceId, code) : [
                     Actions.GetReserveStatus, Actions.Broadcast, Actions.ChangeNickname, Actions.ConfirmEvent, 
                     Actions.ReserveSeat, Actions.Rotation, Actions.TurnTo, Actions.RotateTo, Actions.SetPlayerState, 
                     Actions.GetNeighborPoints, Actions.TurnToFace, Actions.AudienceChangeToVisitor, Actions.RemoveVisitor, 
                     Actions.GetUserWithAvatar, Actions.GetNewUserState, Actions.SetSyncPolicy
-                ].includes(actionType) && 
-            eventsManager.remove(traceId, code, signal)
+                ].includes(actionType)
+            && eventsManager.remove(traceId, code, signal)
         }
 
         const time7 = Date.now();

+ 138 - 139
src/XAnimationController.js

@@ -5,148 +5,147 @@ import Logger from "./Logger.js"
 const logger = new Logger('AnimationController')
 export default class XAnimationController {
     constructor(e) {
-        E(this, "iBodyAnim");
-        E(this, "animations", []);
-        E(this, "defaultAnimation", "Idle");
-        E(this, "onPlay", "Idle");
-        E(this, "loop", !0);
-        E(this, "animationExtras", []);
-        E(this, "enableBlend", !1);
-        E(this, "enableSkLod", !1);
-        E(this, "_boneMap", new Map);
-        E(this, "_lodMask", new Map);
-        E(this, "activeFaceAnimation");
-        E(this, "iFaceAnim");
-        E(this, "_scene");
-        E(this, "_avatar");
-        E(this, "onPlayObservable", new Observable);
-        E(this, "postObserver");
-        E(this, "playAnimation", (e,t,r=0,n,o,a)=>new Promise((s,l)=>{
-            if (this._isPlaying(e, r) || (this._registerAnimInfo(e, t, r, n, o, a),
+        this.iBodyAnim = void 0,
+        this.animations = [],
+        this.defaultAnimation = "Idle",
+        this.onPlay = "Idle",
+        this.loop = !0,
+        this.animationExtras = [],
+        this.enableBlend = !1,
+        this.enableSkLod = !1,
+        this._boneMap = new Map,
+        this._lodMask = new Map,
+        this.activeFaceAnimation = void 0,
+        this.iFaceAnim = void 0,
+        this.onPlayObservable = new Observable,
+        this.playAnimation = (i,o,s=0,c,d,_)=>new Promise((b,k)=>{
+            // zeg 传入i为任意动画名即可播放该动画,比如"GiftClap"
+            // window.room.avatarManager.avatars.get(window.room.userId).playAnimation({"animationName": "GiftClap", "loop":true})
+            if (this._isPlaying(i, s) || (this._registerAnimInfo(i, o, s, c, d, _),
             !this._isAnimate()))
-                return s(null);
-            this._prerocess(e, t),
-            this._avatar.avatarManager.loadAnimation(this._avatar.avatarType, e).then(u=>{
-                if (!u)
-                    return l(new AvatarAnimationError("animation group does not exist"));
-                const c = this._mappingSkeleton(u);
-                if (!c)
-                    return l(new AvatarAnimationError("mapping animation failed"));
-                if (c && this._isAnimationValid(c))
-                    return c.dispose(),
-                    l(new AvatarAnimationError("mapping animation failed"));
-                if (this.enableSkLod && this.skeletonMask(c, r),
-                this.detachAnimation(r),
-                r == 0 ? this.iBodyAnim.animGroup = c : r == 1 && (this.iFaceAnim.animGroup = c),
-                !this._playAnimation(r))
-                    return l(new AvatarAnimationError("[Engine] play animation failed, animtion resource does not match current character"));
+                return b(null);
+            this._prerocess(i, o),
+            this._avatar.avatarManager.loadAnimation(this._avatar.avatarType, i).then(j=>{
+                if (!j)
+                    return k(new AvatarAnimationError("animation group does not exist"));
+                const skeleton = this._mappingSkeleton(j);
+                if (!skeleton)
+                    return k(new AvatarAnimationError("mapping animation failed"));
+                if (skeleton && this._isAnimationValid(skeleton))
+                    return skeleton.dispose(),
+                    k(new AvatarAnimationError("mapping animation failed"));
+                if (this.enableSkLod && this.skeletonMask(skeleton, s),
+                this.detachAnimation(s),
+                s == 0 ? this.iBodyAnim.animGroup = skeleton : s == 1 && (this.iFaceAnim.animGroup = skeleton),
+                !this._playAnimation(s))
+                    return k(new AvatarAnimationError("[Engine] play animation failed, animtion resource does not match current character"));
                 this._playEffect(),
-                this.postObserver = c.onAnimationEndObservable.addOnce(()=>(this._postprocess(r),
-                s(null)))
+                this.postObserver = skeleton.onAnimationEndObservable.addOnce(()=>(this._postprocess(s),
+                b(null)))
             }
             )
         }
-        ));
-        E(this, "stopAnimation", (e=0)=>{
-            var t, r, n, o;
-            switch (e) {
+        ),
+        this.stopAnimation = (i=0)=>{
+            var o, s, c, d;
+            switch (i) {
             case 0:
-                this.iBodyAnim && this.iBodyAnim.animGroup && ((t = this.iBodyAnim) == null || t.animGroup.stop());
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((o = this.iBodyAnim) == null || o.animGroup.stop());
                 break;
             case 1:
-                this.iFaceAnim && this.iFaceAnim.animGroup && ((r = this.iFaceAnim) == null || r.animGroup.stop());
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((s = this.iFaceAnim) == null || s.animGroup.stop());
                 break;
             case 2:
-                this.iBodyAnim && this.iBodyAnim.animGroup && ((n = this.iBodyAnim) == null || n.animGroup.stop()),
-                this.iFaceAnim && this.iFaceAnim.animGroup && ((o = this.iFaceAnim) == null || o.animGroup.stop());
+                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
             }
         }
-        );
-        E(this, "pauseAnimation", (e=0)=>{
-            var t, r, n, o;
-            switch (e) {
+        ,
+        this.pauseAnimation = (i=0)=>{
+            var o, s, c, d;
+            switch (i) {
             case 0:
-                this.iBodyAnim && this.iBodyAnim.animGroup && ((t = this.iBodyAnim) == null || t.animGroup.pause());
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((o = this.iBodyAnim) == null || o.animGroup.pause());
                 break;
             case 1:
-                this.iFaceAnim && this.iFaceAnim.animGroup && ((r = this.iFaceAnim) == null || r.animGroup.pause());
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((s = this.iFaceAnim) == null || s.animGroup.pause());
                 break;
             case 2:
-                this.iBodyAnim && this.iBodyAnim.animGroup && ((n = this.iBodyAnim) == null || n.animGroup.pause()),
-                this.iFaceAnim && this.iFaceAnim.animGroup && ((o = this.iFaceAnim) == null || o.animGroup.pause());
+                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
             }
         }
-        );
-        E(this, "resetAnimation", (e=0)=>{
-            var t, r, n, o;
-            switch (e) {
+        ,
+        this.resetAnimation = (i=0)=>{
+            var o, s, c, d;
+            switch (i) {
             case 0:
-                this.iBodyAnim && this.iBodyAnim.animGroup && ((t = this.iBodyAnim) == null || t.animGroup.reset());
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((o = this.iBodyAnim) == null || o.animGroup.reset());
                 break;
             case 1:
-                this.iFaceAnim && this.iFaceAnim.animGroup && ((r = this.iFaceAnim) == null || r.animGroup.reset());
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((s = this.iFaceAnim) == null || s.animGroup.reset());
                 break;
             case 2:
-                this.iBodyAnim && this.iBodyAnim.animGroup && ((n = this.iBodyAnim) == null || n.animGroup.reset()),
-                this.iFaceAnim && this.iFaceAnim.animGroup && ((o = this.iFaceAnim) == null || o.animGroup.reset());
+                this.iBodyAnim && this.iBodyAnim.animGroup && ((c = this.iBodyAnim) == null || c.animGroup.reset()),
+                this.iFaceAnim && this.iFaceAnim.animGroup && ((d = this.iFaceAnim) == null || d.animGroup.reset());
                 break
             }
         }
-        );
+        ,
         this._avatar = e,
         this._scene = e.avatarManager.scene,
         this.animationExtras.push(action.Cheering.animName),
         this._boneMap = new Map
     }
-    _isPlaying(e, t) {
-        return t == 0 && this.iBodyAnim != null && this.iBodyAnim.animGroup && e == this.iBodyAnim.name ? !0 : !!(t == 1 && this.iFaceAnim != null && this.iFaceAnim.animGroup && e == this.iFaceAnim.name)
+    _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)
     }
     activeAnimation(e=0) {
-        var t, r;
+        var i, o;
         switch (e) {
         case 0:
-            return (t = this.iBodyAnim) == null ? void 0 : t.animGroup;
+            return (i = this.iBodyAnim) == null ? void 0 : i.animGroup;
         case 1:
-            return (r = this.iFaceAnim) == null ? void 0 : r.animGroup;
+            return (o = this.iFaceAnim) == null ? void 0 : o.animGroup;
         default:
             return
         }
     }
-    enableAnimationBlend(e=.1, t=0) {
-        var r, n, o, a;
-        if (t == 0 && ((r = this.iBodyAnim) == null ? void 0 : r.animGroup))
-            for (const s of (n = this.iBodyAnim) == null ? void 0 : n.animGroup.targetedAnimations)
-                s.animation.enableBlending = !0,
-                s.animation.blendingSpeed = e;
-        else if (t == 0 && ((o = this.iFaceAnim) == null ? void 0 : o.animGroup))
-            for (const s of (a = this.iFaceAnim) == null ? void 0 : a.animGroup.targetedAnimations)
-                s.animation.enableBlending = !0,
-                s.animation.blendingSpeed = e
+    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
     }
     disableAnimationBlend(e=0) {
-        var t, r, n, o;
-        if (e == 0 && ((t = this.iBodyAnim) == null ? void 0 : t.animGroup))
-            for (const a of (r = this.iBodyAnim) == null ? void 0 : r.animGroup.targetedAnimations)
-                a.animation.enableBlending = !1;
-        else if (e == 0 && ((n = this.iFaceAnim) == null ? void 0 : n.animGroup))
-            for (const a of (o = this.iFaceAnim) == null ? void 0 : o.animGroup.targetedAnimations)
-                a.animation.enableBlending = !1
+        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
     }
-    skeletonMask(e, t=0) {
-        if (t == 0) {
-            const r = this._lodMask.get(this._avatar.distLevel);
-            if (r)
-                for (let n = 0; n < e.targetedAnimations.length; ++n)
-                    r.includes(e.targetedAnimations[n].target.name) || (e.targetedAnimations.splice(n, 1),
-                    n--);
+    skeletonMask(e, i=0) {
+        if (i == 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--);
             return !0
         }
         return !1
     }
     detachAnimation(e=2) {
-        var t, r;
+        var i, o;
         switch (e) {
         case 0:
             this.iBodyAnim && this.iBodyAnim.animGroup && (this.iBodyAnim.animGroup._parentContainer.xReferenceCount && this.iBodyAnim.animGroup._parentContainer.xReferenceCount--,
@@ -162,8 +161,8 @@ export default class XAnimationController {
             break;
         case 2:
             this.iBodyAnim && this.iBodyAnim.animGroup && (this.iBodyAnim.animGroup._parentContainer.xReferenceCount && this.iBodyAnim.animGroup._parentContainer.xReferenceCount--,
-            (t = this.iBodyAnim) == null || t.animGroup.stop(),
-            (r = this.iBodyAnim) == null || r.animGroup.dispose(),
+            (i = this.iBodyAnim) == null || i.animGroup.stop(),
+            (o = this.iBodyAnim) == null || o.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(),
@@ -173,95 +172,95 @@ export default class XAnimationController {
         }
     }
     blendAnimation() {}
-    getAnimation(e, t) {
-        return avatarLoader.animations.get(getAnimationKey(t, e))
+    getAnimation(e, i) {
+        return avatarLoader.animations.get(getAnimationKey(i, e))
     }
     _mappingSkeleton(e) {
         if (e) {
-            const t = e.clone(e.name, r=>{
-                var o, a, s;
-                const n = r.name.split(" ").length > 2 ? r.name.split(" ")[2] : r.name;
-                if (this._boneMap.size === ((o = this._avatar.skeleton) == null ? void 0 : o.bones.length))
-                    return this._boneMap.get(n);
+            const i = e.clone(e.name, o=>{
+                var c, d, _;
+                const s = o.name.split(" ").length > 2 ? o.name.split(" ")[2] : o.name;
+                if (this._boneMap.size === ((c = this._avatar.skeleton) == null ? void 0 : c.bones.length))
+                    return this._boneMap.get(s);
                 {
-                    const l = (s = (a = this._avatar.skeleton) == null ? void 0 : a.bones.find(u=>u.name === r.name || u.name === r.name.split(" ")[2])) == null ? void 0 : s.getTransformNode();
-                    return l && (l.name = n,
-                    this._boneMap.set(n, l)),
-                    l
+                    const b = (_ = (d = this._avatar.skeleton) == null ? void 0 : d.bones.find(k=>k.name === o.name || k.name === o.name.split(" ")[2])) == null ? void 0 : _.getTransformNode();
+                    return b && (b.name = s,
+                    this._boneMap.set(s, b)),
+                    b
                 }
             }
             );
-            return t._parentContainer = e._parentContainer,
-            t
+            return i._parentContainer = e._parentContainer,
+            i
         } else
             return
     }
     removeAnimation(e) {
-        const t = avatarLoader.containers.get(e.name);
-        t && (t.dispose(),
+        const i = avatarLoader.containers.get(e.name);
+        i && (i.dispose(),
         avatarLoader.containers.delete(e.name),
         avatarLoader.animations.delete(getAnimationKey(e.name, e.skType)))
     }
-    _setPosition(e, t) {
+    _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)
     }
-    _registerAnimInfo(e, t, r=0, n, o, a) {
-        const s = {
+    _registerAnimInfo(e, i, o=0, s, c, d) {
+        const _ = {
             name: e,
             skType: this._avatar.avatarType,
-            loop: t,
-            playSpeed: n,
+            loop: i,
+            playSpeed: s,
             currentFrame: 0,
-            startFrame: o,
-            endFrame: a
+            startFrame: c,
+            endFrame: d
         };
-        r == 0 ? this.iBodyAnim == null ? this.iBodyAnim = s : (this.iBodyAnim.name = e,
+        o == 0 ? this.iBodyAnim == null ? this.iBodyAnim = _ : (this.iBodyAnim.name = e,
         this.iBodyAnim.skType = this._avatar.avatarType,
-        this.iBodyAnim.loop = t,
-        this.iBodyAnim.playSpeed = n,
+        this.iBodyAnim.loop = i,
+        this.iBodyAnim.playSpeed = s,
         this.iBodyAnim.currentFrame = 0,
-        this.iBodyAnim.startFrame = o,
-        this.iBodyAnim.endFrame = a) : r == 1 && (this.iFaceAnim == null ? this.iFaceAnim = s : (this.iFaceAnim.name = e,
+        this.iBodyAnim.startFrame = c,
+        this.iBodyAnim.endFrame = d) : o == 1 && (this.iFaceAnim == null ? this.iFaceAnim = _ : (this.iFaceAnim.name = e,
         this.iFaceAnim.skType = this._avatar.avatarType,
-        this.iFaceAnim.loop = t,
-        this.iFaceAnim.playSpeed = n,
+        this.iFaceAnim.loop = i,
+        this.iFaceAnim.playSpeed = s,
         this.iFaceAnim.currentFrame = 0,
-        this.iFaceAnim.startFrame = o,
-        this.iFaceAnim.endFrame = a)),
+        this.iFaceAnim.startFrame = c,
+        this.iFaceAnim.endFrame = d)),
         this.onPlay = e,
-        this.loop = t
+        this.loop = i
     }
     _isAnimate() {
         var e;
         return !(!this._avatar.isRender || !this._avatar.skeleton || ((e = this._avatar.rootNode) == null ? void 0 : e.getChildMeshes().length) == 0)
     }
-    _prerocess(e, t) {
-        this._avatar.isRayCastEnable && this._setPosition(e, t),
+    _prerocess(e, i) {
+        this._avatar.isRayCastEnable && this._setPosition(e, i),
         this._avatar.priority === 0 && logger.info(`start play animation: ${e} on avatar ${this._avatar.id}`)
     }
     _playEffect() {
-        this.animationExtras.indexOf(this.iBodyAnim.name) != -1 && action.Cheering.attachPair.forEach(t=>{
-            this._avatar.attachExtraProp(t.obj, t.bone, new BABYLON.Vector3(t.offset.x,t.offset.y,t.offset.z), new BABYLON.Vector3(t.rotate.x,t.rotate.y,t.rotate.z)),
-            this._avatar.showExtra(t.obj)
+        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(e=0) {
-        var t, r;
-        return e == 0 && this.iBodyAnim && ((t = this.iBodyAnim) == null ? void 0 : t.animGroup) ? (this.onPlayObservable.notifyObservers(this._scene),
+        var i, o;
+        return e == 0 && this.iBodyAnim && ((i = this.iBodyAnim) == null ? void 0 : i.animGroup) ? (this.onPlayObservable.notifyObservers(this._scene),
         this.iBodyAnim.animGroup.start(this.loop, this.iBodyAnim.playSpeed, this.iBodyAnim.startFrame, this.iBodyAnim.endFrame, !1),
-        !0) : e == 1 && this.iFaceAnim && ((r = this.iFaceAnim) == null ? void 0 : r.animGroup) ? (this.iFaceAnim.animGroup.start(this.loop, this.iFaceAnim.playSpeed, this.iFaceAnim.startFrame, this.iFaceAnim.endFrame, !1),
+        !0) : e == 1 && this.iFaceAnim && ((o = this.iFaceAnim) == null ? void 0 : o.animGroup) ? (this.iFaceAnim.animGroup.start(this.loop, this.iFaceAnim.playSpeed, this.iFaceAnim.startFrame, this.iFaceAnim.endFrame, !1),
         !0) : !1
     }
     _postprocess(e) {
-        var r, n;
-        let t;
-        e == 0 ? t = (r = this.iBodyAnim) == null ? void 0 : r.name : e == 1 && (t = (n = this.iFaceAnim) == null ? void 0 : n.name),
-        t === action.Cheering.animName && this._avatar.disposeExtra()
+        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()
     }
     _isAnimationValid(e) {
-        for (let t = 0; t < e.targetedAnimations.length; ++t)
-            if (e.targetedAnimations[t].target)
+        for (let i = 0; i < e.targetedAnimations.length; ++i)
+            if (e.targetedAnimations[i].target)
                 return !1;
         return !0
     }

+ 296 - 189
src/XAvatar.js

@@ -11,407 +11,514 @@ const castRayOffsetY = .01;
 const castRayTeleportationOffset = 10;
 
 export default class XAvatar {
-    constructor({id: e, avatarType: t, priority: r, avatarManager: n, assets: o, status: a}) {
-        E(this, "id", "-1");
-        E(this, "priority", 0);
-        E(this, "isRender", !1);
-        E(this, "distLevel", 0);
-        E(this, "isInLoadingList", !1);
-        E(this, "isHide", !1);
-        E(this, "component");
-        E(this, "controller");
-        E(this, "stateMachine");
-        E(this, "bbComponent");
-        E(this, "_avatarType");
-        E(this, "clothesList", []);
-        E(this, "isSelected", !1);
-        E(this, "pendingLod", !1);
-        E(this, "_previousReceivedPosition", new BABYLON.Vector3(0,1e4,0));
-        E(this, "_avatarPosition");
-        E(this, "_avatarRotation");
-        E(this, "_avatarScale");
-        E(this, "rootNode");
-        E(this, "distToCam", 1e11);
-        E(this, "enableNickname", !0);
-        E(this, "distance", 1e11);
-        E(this, "isCulling", !1);
-        E(this, "reslevel", 0);
-        E(this, "isInLoadingQueue", !1);
-        E(this, "_isRayCastEnable");
-        E(this, "_scene");
-        E(this, "_avatarManager");
-        E(this, "_transparent", 0);
-        E(this, "hide", ()=>(this.isHide = !0,
-        this._hide(),
-        !this.isRender));
-        E(this, "_show", ()=>{
-            var e;
-            this.isHide || (this.setIsPickable(!0),
-            this.priority == 0 && (this.rootNode.setEnabled(!0),
-            this.isRender = !0,
-            this.avatarManager._updateBillboardStatus(this, BillboardStatus.SHOW),
-            (e = this.controller) == null || e.playAnimation(this.controller.onPlay, this.controller.loop)))
-        }
-        );
-        E(this, "show", ()=>(this.isHide = !1,
-        this._show(),
-        !!this.isRender));
-        E(this, "setAnimations", e=>{
-            this.controller.animations = e
-        }
-        );
-        E(this, "attachToAvatar", (e,t=!1,r={
-            x: 0,
-            y: 0,
-            z: 0
-        },n=!1,o,a)=>this.bbComponent.attachToAvatar(this, e, t, r, n, o, a));
-        E(this, "detachFromAvatar", (e,t=!1)=>this.bbComponent.detachFromAvatar(this, e, t));
-        E(this, "getBbox", (e={})=>this.bbComponent.getBbox(this, e));
-        this.id = e,
-        this._avatarManager = n,
+    constructor({id, avatarType, priority, avatarManager, assets, status}) {
+        this.id = "-1",
+        this.priority = 0,
+        this.isRender = !1,
+        this.distLevel = 0,
+        this.isInLoadingList = !1,
+        this.isHide = !1,
+        this.clothesList = [],
+        this.isSelected = !1,
+        this.pendingLod = !1,
+        this._previousReceivedPosition = new BABYLON.Vector3(0,1e4,0),
+        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.hide = ()=>{
+            this.isHide = !0
+            this._hide()
+            return !this.isRender
+        },
+
+        this._show = ()=>{
+            this.isHide || (
+                this.setIsPickable(!0),
+                this.bbComponent._attachmentObservers.forEach((b,k)=>{
+                    k.setEnabled(!0)
+                }),
+                this.priority == 0 && (
+                    this.rootNode.setEnabled(!0),
+                    this.isRender = !0,
+                    this.avatarManager._updateBillboardStatus(this, BillboardStatus.SHOW),
+                    this.component.accessories.forEach(b=>{
+                        b.rootComponent.setEnabled(!0)
+                    }),
+                    this.controller == null || this.controller.playAnimation(this.controller.onPlay, this.controller.loop)
+                ),
+                this.component.accessories.forEach(b=>{
+                    b.rootComponent.setEnabled(!0)
+                })
+            )
+        },
+
+        this.show = ()=>{
+            this.isHide = !1
+            this._show()
+            return !!this.isRender
+        },
+
+        this.setAnimations = _=>{
+            this.controller.animations = _
+        },
+        
+        this.attachToAvatar = ( _, b=!1, k={x:0,y:0,z:0}, j=!1, $, _e ) => {
+            this.bbComponent.attachToAvatar(this, _, b, k, j, _e)
+        },
+
+        this.detachFromAvatar = ( _, b=!1 )=>{
+            this.bbComponent.detachFromAvatar(this, _, b)
+        },
+        this.getBbox = (_={})=>{
+            this.bbComponent.getBbox(this, _)
+        },
+
+        this.id = id,
+        this._avatarManager = avatarManager,
         this._scene = this.avatarManager.scene,
-        this.clothesList = o,
-        this._avatarType = t,
-        this.priority = r || 0,
+        this.clothesList = assets,
+        this._avatarType = avatarType,
+        this.priority = priority || 0,
+        
         this.controller = new XAnimationController(this),
         this.component = new XAvatarComopnent,
         this.stateMachine = new XStateMachine(this._scene),
         this.bbComponent = new XAvatarBillboardComponent(this._scene),
-        this.rootNode = new BABYLON.TransformNode(e,this._avatarManager.scene),
-        this._avatarScale = a.avatarScale == null ? 1 : a.avatarScale,
-        this._avatarRotation = a.avatarRotation == null ? {
-            pitch: 0,
-            yaw: 0,
-            roll: 0
-        } : a.avatarRotation,
-        this._avatarPosition = a.avatarPosition == null ? {
-            x: 0,
-            y: 0,
-            z: 0
-        } : a.avatarPosition,
-        this.setPosition(this._avatarPosition),
+        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._isRayCastEnable = avatarSetting.isRayCastEnable,
+        
+        this.setPosition(this._avatarPosition, !0),
         this.setRotation(this._avatarRotation),
         this.setScale(this.scale),
         this._isRayCastEnable = avatarSetting.isRayCastEnable,
+
         this._scene.registerBeforeRender(()=>{
             this.tick()
-        }
-        )
+        })
     }
+
     tick() {
         this.cullingTick()
     }
+
     cullingTick() {
-        var e;
-        this.isCulling && ((e = this.rootNode) == null || e.getChildMeshes().forEach(t=>{
-            this.distToCam < 50 ? t.visibility = 0 : t.visibility = this._transparent
-        }
-        ))
+        this.isCulling && (this.rootNode == null || this.rootNode.getChildMeshes().forEach(i=>{
+            this.distToCam < 50 ? i.visibility = 0 : i.visibility = this._transparent
+        }))
     }
+
     setTransParentThresh(e) {
         this._transparent = e
     }
+
     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
     }
+
     setNicknameStatus(e) {
         return this.bbComponent.setNicknameStatus(e)
     }
+
     setBubbleStatus(e) {
         return this.bbComponent.setBubbleStatus(e)
     }
+
     setButtonsStatus(e) {
         return this.bbComponent.setBubbleStatus(e)
     }
+
     setGiftButtonsVisible(e) {
         return this.bbComponent.setGiftButtonsVisible(e)
     }
+
     get avatarType() {
         return this._avatarType
     }
+
     attachBody(e) {
         return this.component.addBodyComp(this, e)
     }
+
     attachDecoration(e) {
         return this.component.addClothesComp(this, e)
     }
+    
     detachDecoration(e) {
         return this.component.clearClothesComp(e)
     }
+
     detachDecorationAll() {
         return this.component.clearAllClothesComps()
     }
+
     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.bbComponent.updateBillboardStatus(this, BillboardStatus.SHOW),
         this.isCulling = !1)
     }
+
     _hide() {
         !this.isHide || (this.setIsPickable(!1),
+        this.bbComponent._attachmentObservers.forEach((e,i)=>{
+            i.setEnabled(!1)
+        }
+        ),
         this.priority == 0 ? (this.rootNode.setEnabled(!1),
         this.isRender = !1,
-        this.bbComponent.updateBillboardStatus(this, BillboardStatus.HIDE)) : this.isRender && (this.avatarManager.currentLODUsers[this.distLevel]--,
-        this.removeAvatarFromScene()))
+        this.bbComponent.updateBillboardStatus(this, BillboardStatus.HIDE),
+        this.component.accessories.forEach(e=>{
+            e.rootComponent.setEnabled(!1)
+        }
+        )) : this.isRender && (this.avatarManager.currentLODUsers[this.distLevel]--,
+        this.removeAvatarFromScene()),
+        this.component.accessories.forEach(e=>{
+            e.rootComponent.setEnabled(!1)
+        }))
     }
-    rotate(e, t, r) {
-        return this.stateMachine.roll(this, e, t, r)
+
+    rotate(e, i, o) {
+        return this.stateMachine.roll(this, e, i, o)
     }
+
     set isRayCastEnable(e) {
         this._isRayCastEnable = e
     }
+
     get isRayCastEnable() {
         return this._isRayCastEnable
     }
+
     getAvatarId() {
         return this.id
     }
+
     getAvaliableAnimations() {
         const e = avatarLoader.avaliableAnimation.get(this.avatarType);
         return e || []
     }
-    setPosition(e, t=!1) {
-        if (this._avatarPosition = e,
-        this.rootNode) {
-            const r = ue4Position2Xverse(this._avatarPosition);
-            let n = !1;
-            this.avatarManager.getMainAvatar() && (this.id != this.avatarManager.getMainAvatar().id || (Math.abs(r.y - this._previousReceivedPosition.y) > castRayOffsetY && (n = !0),
-            r.subtract(this._previousReceivedPosition).length() > castRayTeleportationOffset && (n = !0))),
-            this._isRayCastEnable ? n || t ? this._castRay(e).then(o=>{
-                this.rootNode.position = r,
-                this.rootNode.position.y -= o
-            }
-            ).catch(o=>{
-                Promise.reject(o)
+
+    // 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)
+                }
             }
-            ) : (this.rootNode.position.x = r.x,
-            this.rootNode.position.z = r.z) : this.rootNode.position = r,
-            this._previousReceivedPosition = r.clone()
+            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,
         this.rootNode) {
-            const t = {
+            const i = {
                 pitch: e.pitch,
                 yaw: e.yaw + 180,
                 roll: e.roll
             }
-              , r = ue4Rotation2Xverse(t);
-            this.rootNode.rotation = r
+              , o = ue4Rotation2Xverse(i);
+            this.rootNode.rotation = o
         }
     }
+
     setAvatarVisible(e) {
         this.rootNode && (this.rootNode.setEnabled(e),
-        this.rootNode.getChildMeshes().forEach(t=>{
-            t.setEnabled(e)
+        this.rootNode.getChildMeshes().forEach(i=>{
+            i.setEnabled(e)
         }
         ))
     }
+
     setScale(e) {
         this._avatarScale = e,
         this.rootNode && (this.rootNode.scaling = new BABYLON.Vector3(e,e,e)),
         this.bbComponent.bbox && this.getBbox()
     }
+
     _removeAvatarFromScene() {
-        var e, t;
+        var e, i;
         this.isRender = !1,
         (e = this.controller) == null || e.detachAnimation(),
         this.component.dispose(this),
-        (t = this.avatarManager.sceneManager) == null || t.lightComponent.removeShadow(this)
+        (i = this.avatarManager.sceneManager) == null || i.lightComponent.removeShadow(this),
+        this.component.accessories.forEach(o=>{
+            o.rootComponent.setEnabled(!1)
+        })
     }
+
     removeAvatarFromScene() {
         this._removeAvatarFromScene(),
         this._disposeBillBoard()
     }
+
     _disposeBillBoard() {
         this.bbComponent.disposeBillBoard(this)
     }
-    addComponent(e, t, r, n) {
-        return this.component.changeClothesComp(this, e, t, r, n)
+
+    addComponent(e, i, o, s) {
+        return i === "pendant" ? this.component.attachPendant(this, e) : this.component.changeClothesComp(this, e, i, o, s)
     }
-    _castRay(e) {
-        return new Promise((t,r)=>{
-            var d;
-            const n = ue4Position2Xverse(e)
-              , o = new BABYLON.Vector3(0,-1,0)
-              , a = 1.5 * this.scale
-              , s = 100 * a
-              , l = a
-              , u = new BABYLON.Vector3(n.x,n.y + l,+n.z)
-              , c = new BABYLON.Ray(u,o,s)
-              , h = (d = this.avatarManager.sceneManager) == null ? void 0 : d.getGround(e);
-            if (!h || h.length <= 0)
-                return logger.warn(`\u89D2\u8272 id= ${this.id} \u627E\u4E0D\u5230\u5730\u9762\uFF0C\u5F53\u524D\u9AD8\u5EA6\u4E3A\u4E0B\u53D1\u9AD8\u5EA6`),
-                t(0);
-            let f = c.intersectsMeshes(h);
-            if (f.length > 0)
-                return t(f[0].distance - l);
-            if (o.y = 1,
-            f = c.intersectsMeshes(h),
-            f.length > 0)
-                return t(-(f[0].distance - l))
+
+    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))
         }
-        )
     }
+
+    getComponentByType(e, i) {
+        if (e === "pendant")
+            if (i) {
+                const o = this.component.accessories.get(i);
+                return o || []
+            } else
+                return Array.from(this.component.accessories).map(o=>o[1]);
+        else
+            return this.component.resourceIdList.find(o=>o.type == e)
+    }
+
+    _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)
+                return log$F.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(e) {
         return this.bbComponent.setPickBoxScale(e)
     }
+
     setIsPickable(e) {
         return this.bbComponent.setIsPickable(this, e)
     }
+
     createPickBoundingbox(e) {
         return this.bbComponent.createPickBoundingbox(this, e)
     }
+
     scaleBbox(e) {
         this.bbComponent.bbox && this.bbComponent.bbox.scale(e)
     }
-    rotateTo(e, t, r) {
-        return this.stateMachine.rotateTo(this, e, t, r)
+
+    rotateTo(e, i, o) {
+        return this.stateMachine.rotateTo(this, e, i, o)
     }
-    faceTo(e, t) {
-        return this.stateMachine.lookAt(this, e, t)
+
+    faceTo(e, i) {
+        return this.stateMachine.lookAt(this, e, i)
     }
+
     removeObserver() {
         this.stateMachine.disposeObsever()
     }
-    move(e, t, r, n, o) {
-        return this.stateMachine.moveTo(this, e, t, r, n, o)
+
+    moveHermite(e, i, o, s, c, d) {
+        return this.stateMachine.moveToHermite(this, e, i, o, s, c, d)
     }
+
+    moveCardinal(e, i, o, s, c, d, _=!1) {
+        return this.stateMachine.moveToCardinal(this, e, i, o, s, c, d, _)
+    }
+
+    move(e, i, o, s, c, d=!1) {
+        return this.stateMachine.moveTo(this, e, i, o, s, c, d)
+    }
+
     initNameboard(e=1) {
         return this.bbComponent.initNameboard(this, e)
     }
+
     initBubble(e=1) {
         return this.bbComponent.initBubble(this, e)
     }
-    say(e, {id: t, isUser: r, background: n, font: o="Arial", fontsize: a=38, fontcolor: s="#ffffff", fontstyle: l="bold", linesize: u=22, linelimit: c, offsets: h={
-        x: 0,
-        y: 0,
-        z: 40
-    }, scale: f=this._avatarScale, compensationZ: d=11.2, reregistAnyway: _=!0}) {
+
+    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: t,
-            isUser: r,
-            background: n,
-            font: o,
-            fontsize: a,
-            fontcolor: s,
-            fontstyle: l,
-            linesize: u,
-            linelimit: c,
-            offsets: h,
-            scale: f,
-            compensationZ: d,
-            reregistAnyway: _
+            id, isUser, background, 
+            font, fontsize, fontcolor, fontstyle, linesize, linelimit,
+            offsets, scale, compensationZ, reregistAnyway
         })
     }
+    
     silent() {
         return this.bbComponent.silent()
     }
-    setNickName(e, {id: t, isUser: r, background: n, font: o="Arial", fontsize: a=40, fontcolor: s="#ffffff", fontstyle: l="bold", linesize: u=22, linelimit: c, offsets: h={
-        x: 0,
-        y: 0,
-        z: 15
-    }, scale: f=this._avatarScale, compensationZ: d=0, reregistAnyway: _=!1}) {
+    
+    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: t,
-            isUser: r,
-            background: n,
-            font: o,
-            fontsize: a,
-            fontcolor: s,
-            fontstyle: l,
-            linesize: u,
-            linelimit: c,
-            offsets: h,
-            scale: f,
-            compensationZ: d,
-            reregistAnyway: _
+            id, isUser, background,
+            font, fontsize, fontcolor, fontstyle, linesize, linelimit,
+            offsets, scale, compensationZ, reregistAnyway
         })
     }
-    generateButtons(e=null, t=this._avatarScale, r=85) {
-        return this.bbComponent.generateButtons(this, e, t, r)
+
+    generateButtons(e=null, i=this._avatarScale, o=85) {
+        return this.bbComponent.generateButtons(this, e, i, o)
     }
+
     clearButtons() {
         return this.bbComponent.clearButtons()
     }
-    attachExtraProp(e, t, r, n) {
-        return this.component.addDecoComp(this, e, t, r, n)
+
+    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 t;
+        var i;
         if (this.skeleton) {
-            const r = this.skeleton.bones.find(n=>n.name.replace("Clone of ", "") == e);
-            if (r && r.getTransformNode() && ((t = r.getTransformNode()) == null ? void 0 : t.position)) {
-                const n = r.getTransformNode().position;
+            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;
                 return xversePosition2Ue4({
-                    x: n.x,
-                    y: n.y,
-                    z: n.z
+                    x: s.x,
+                    y: s.y,
+                    z: s.z
                 })
             }
         }
     }
-    shootTo(e, t, r=2, n=10, o={
+
+    shootTo(e, i, o=2, s=10, c={
         x: 0,
         y: 0,
         z: 150
     }) {
-        return this.stateMachine.sendObjectTo(this, e, t, r, n, o)
+        return this.stateMachine.sendObjectTo(this, e, i, o, s, c)
     }
 }

+ 103 - 88
src/XAvatarComopnent.js

@@ -5,63 +5,61 @@ const logger = new Logger('XAvatarComopnent')
 
 export default class XAvatarComopnent {
     constructor() {
-        E(this, "resourceIdList", []);
-        E(this, "skeleton");
-        E(this, "extraProp");
-        E(this, "extras", []);
-        E(this, "body")
+        this.resourceIdList = [],
+        this.skeleton = void 0,
+        this.extraProp = void 0,
+        this.extras = [],
+        this.body = void 0,
+        this.accessories = new Map
     }
-    addBodyComp(e, t) {
-        // console.error(this, e, t)
-        return !e.rootNode || t.root.getChildMeshes().length === 0 ? (t.isRender = !1,
-        !1) : (this.body = t,
+    addBodyComp(e, i) {
+        return !e.rootNode || i.root.getChildMeshes().length === 0 ? (i.isRender = !1,
+        !1) : (this.body = i,
         this.body.root.parent = e.rootNode,
-        t.isRender = !0,
+        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 = t.skeleton,
+        this.skeleton = i.skeleton,
         !0)
     }
-    addClothesComp(e, t) {
-        // console.error(t.root.name)
-        // console.error(this, e, t)
-        return !e.rootNode || !this.skeleton || !t.root ? (t.isRender = !1,
-        !1) : (t.root.xtype = EMeshType.XAvatar,
-        t.root.xid = e.id,
-        t.isRender = !0,
-        t.root.parent = e.rootNode.getChildMeshes()[0],
-        this.resourceIdList.push(t),
-        t.root.skeleton = this.skeleton,
-        t.root.getChildMeshes().forEach(r=>{
-            r.skeleton = this.skeleton
+    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
         }
         ),
         !0)
     }
     clearClothesComp(e) {
-        e.root.getChildMeshes().forEach(t=>{
-            t.skeleton = null,
-            t.dispose(),
-            t.xid = void 0
+        e.root.getChildMeshes().forEach(i=>{
+            i.skeleton = null,
+            i.dispose(),
+            i.xid = void 0
         }
         ),
         e.root.dispose(),
-        this.resourceIdList = this.resourceIdList.filter(t=>t.uId != e.uId)
+        this.resourceIdList = this.resourceIdList.filter(i=>i.uId != e.uId)
     }
     clearAllClothesComps() {
         this.resourceIdList.forEach(e=>{
-            var t;
+            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(r=>{
-                r.skeleton = null,
-                r.dispose()
+            e.root.getChildMeshes().forEach(o=>{
+                o.skeleton = null,
+                o.dispose()
             }
             ),
-            (t = e.root.skeleton) == null || t.dispose(),
+            (i = e.root.skeleton) == null || i.dispose(),
             e.root.dispose()
         }
         ),
@@ -77,92 +75,109 @@ export default class XAvatarComopnent {
         this.body.root.dispose(),
         this.body = void 0,
         this.skeleton && (this.skeleton.dispose(),
-        this.skeleton = void 0)) : logger.warn("[Engine] no body to dispose")
+        this.skeleton = void 0)) : log$I.warn("[Engine] no body to dispose")
+    }
+    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
+        }
+        ))
+    }
+    detachPendant(e, i=!0) {
+        const o = this.accessories.get(e);
+        o && (o.dispose(),
+        this.accessories.delete(e))
     }
-    changeClothesComp(e, t, r, n, o) {
-        return new Promise(a=>{
-            if (r === "pendant" || this.resourceIdList.some(s=>s.name === t))
-                return a();
+    changeClothesComp(e, i, o, s, c) {
+        return new Promise(d=>{
+            if (this.resourceIdList.some(_=>_.name === i))
+                return d();
             if (e.isHide || !e.isRender)
-                o.concat(r).forEach(l=>{
-                    e.clothesList = e.clothesList.filter(c=>c.type != l);
-                    const u = {
-                        type: r,
-                        id: t,
-                        url: n,
+                c.concat(o).forEach(b=>{
+                    e.clothesList = e.clothesList.filter(j=>j.type != b);
+                    const k = {
+                        type: o,
+                        id: i,
+                        url: s,
                         lod: 0
                     };
-                    e.clothesList.push(u)
+                    e.clothesList.push(k)
                 }
                 ),
-                a();
+                d();
             else {
-                const s = o.concat(r);
-                e.avatarManager.loadDecoration(r, t, 0).then(l=>{
-                    if (l) {
-                        e.attachDecoration(l);
-                        const u = {
-                            type: r,
-                            id: t,
-                            url: n
+                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
                         };
-                        e.clothesList.push(u),
-                        l.root.setEnabled(!0),
-                        s.forEach(c=>{
-                            const h = this.resourceIdList.filter(f=>f.type === c);
-                            if (h.length > 1) {
-                                const f = h.filter(d=>d.name === t);
-                                if (f.length > 1)
-                                    for (let d = 1; d < f.length; ++d) {
-                                        e.detachDecoration(f[d]),
-                                        e.clothesList = e.clothesList.filter(g=>g.id != f[d].name);
-                                        const _ = {
-                                            type: r,
-                                            id: t,
-                                            url: n
+                        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(_)
+                                        e.clothesList.push(tt)
                                     }
                             }
-                            h[0] && h[0].name != t && this._readyToDetach(e, r) && (e.detachDecoration(h[0]),
-                            e.clothesList = e.clothesList.filter(f=>f.id != h[0].name))
+                            $[0] && $[0].name != i && this._readyToDetach(e, o) && (e.detachDecoration($[0]),
+                            e.clothesList = e.clothesList.filter(_e=>_e.id != $[0].name))
                         }
                         )
                     }
-                    return a()
+                    return d()
                 }
                 )
             }
         }
         )
     }
-    _readyToDetach(e, t) {
-        return !((t == "clothes" || t == "pants") && e.clothesList.filter(n=>n.type === "suit").length == 1 && (!e.clothesList.some(n=>n.type === "pants") || !e.clothesList.some(n=>n.type === "clothes")))
+    _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, t, r, n, o) {
+    addDecoComp(e, i, o, s, c) {
         if (e.isRender) {
-            const a = e.avatarManager.extraComps.get(t)
-              , s = a == null ? void 0 : a.clone(t, void 0);
-            if (!a) {
-                logger.error("\u6CA1\u6709\u5BF9\u5E94\u7684\u7EC4\u4EF6");
+            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(s);
-            const l = this.skeleton.bones.find(u=>u.name === r);
-            s.position = n,
-            s.rotation = o,
-            s.attachToBone(l, e.rootNode.getChildMeshes()[0])
+            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(t=>{
-            t.name.indexOf(e) > 0 && t.setEnabled(!0)
+        this.extras.forEach(i=>{
+            i.name.indexOf(e) > 0 && i.setEnabled(!0)
         }
         )
     }
     hideExtra(e) {
-        this.extras.forEach(t=>{
-            t.name.indexOf(e) > 0 && t.setEnabled(!1)
+        this.extras.forEach(i=>{
+            i.name.indexOf(e) > 0 && i.setEnabled(!1)
         }
         )
     }

+ 264 - 229
src/XAvatarLoader.js

@@ -1,120 +1,158 @@
+import Logger from "./Logger.js"
+
+const logger = new Logger('XAvatarLoader')
+
 export default class XAvatarLoader {
     constructor() {
-        E(this, "containers", new Map);
-        E(this, "meshes", new Map);
-        E(this, "animations", new Map);
-        E(this, "aniPath", new Map);
-        E(this, "binPath", new Map);
-        E(this, "texPath", new Map);
-        E(this, "matPath", new Map);
-        E(this, "mshPath", new Map);
-        E(this, "rootPath", new Map);
-        E(this, "meshTexList", new Map);
-        E(this, "_enableIdb", !0);
-        E(this, "_mappings", new Map);
-        E(this, "_sharedTex", new Map);
-        E(this, "avaliableAnimation", new Map);
-        E(this, "enableShareTexture", !0);
-        E(this, "enableShareAnimation", !0);
-        E(this, "fillEmptyLod", !0);
+        this.containers = new Map,
+        this.meshes = new Map,
+        this.animations = 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.meshTexList = new Map,
+        this._enableIdb = !0,
+        this._mappings = new Map,
+        this._sharedTex = new Map,
+        this.avaliableAnimation = new Map,
+        this.enableShareTexture = !0,
+        this.enableShareAnimation = !0,
+        this.fillEmptyLod = !0,
+        this.pendantMap = new Map;
         const e = new BABYLON.GLTFFileLoader;
         BABYLON.SceneLoader.RegisterPlugin(e),
-        e.preprocessUrlAsync = function(t) {
-            const r = avatarLoader._mappings.get(t);
-            return r ? Promise.resolve(r) : Promise.resolve(t)
+        e.preprocessUrlAsync = function(i) {
+            const o = avatarLoader._mappings.get(i);
+            return o ? Promise.resolve(o) : Promise.resolve(i)
+        }
+    }
+    _parsePendant(e, i) {
+        if (!e || !i) {
+            logger.error("[Engine] invalid id or url when loading pendant");
+            return
+        }
+        const o = ".zip"
+          , s = i.replace(o, "/");
+        this.pendantMap.set(e, s)
+    }
+    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)
         }
+        )
     }
-    getParsedUrl(e, t, r, n="") {
-        return new Promise((o,a)=>{
-            if (!r || r.indexOf(".zip") === -1)
-                return o(r);
-            const s = this.rootPath.get(r);
-            if (s)
-                return o(s);
+    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(_);
             {
-                const l = ".zip"
-                  , u = r.replace(l, "") + COMPONENT_LIST_PREFIX;
-                e.urlTransformer(u, !0).then(c=>{
-                    if (!c)
-                        return a("Loading Failed");
-                    new Response(c).json().then(h=>{
-                        var _, g, m, v, y, b, T;
-                        const f = r.replace(l, "")
-                          , d = f + ((_ = h == null ? void 0 : h.components) == null ? void 0 : _.url.replace("./", ""));
-                        if (this.rootPath.set(r, d),
-                        h.components ? (h.components.url && this.mshPath.set(t, f + "/" + ((g = h == null ? void 0 : h.components) == null ? void 0 : g.url.replace("./", ""))),
-                        h.components.url_lod2 && this.mshPath.set(t + "_" + avatarSetting.lod[1].level, f + "/" + ((m = h == null ? void 0 : h.components) == null ? void 0 : m.url_lod2.replace("./", ""))),
-                        h.components.url_lod4 && this.mshPath.set(t + "_" + avatarSetting.lod[2].level, f + "/" + ((v = h == null ? void 0 : h.components) == null ? void 0 : v.url_lod4.replace("./", "")))) : (h.meshes.url && this.mshPath.set(t, f + "/" + ((y = h == null ? void 0 : h.meshes) == null ? void 0 : y.url.replace("./", ""))),
-                        h.meshes.url_lod2 && this.mshPath.set(t + "_" + avatarSetting.lod[1].level, f + "/" + ((b = h == null ? void 0 : h.meshes) == null ? void 0 : b.url_lod2.replace("./", ""))),
-                        h.meshes.url_lod4 && this.mshPath.set(t + "_" + avatarSetting.lod[2].level, f + "/" + ((T = h == null ? void 0 : h.meshes) == null ? void 0 : T.url_lod4.replace("./", "")))),
-                        h.materials && h.materials.forEach(C=>{
-                            const A = f + "/" + C.url;
-                            this.matPath.set(C.name, A)
+                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)
                         }
                         ),
-                        h.bin) {
-                            const C = f + "/" + h.bin.url;
-                            this.binPath.set(t, C);
-                            const A = f + "/" + h.bin.url_lod2;
-                            this.binPath.set(t + "_" + avatarSetting.lod[1].level, A);
-                            const S = f + "/" + h.bin.url_lod4;
-                            this.binPath.set(t + "_" + avatarSetting.lod[2].level, S)
+                        $.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)
                         }
-                        return h.textures && h.textures.forEach(C=>{
-                            const A = f + "/" + C.url;
-                            this.texPath.set(C.url, A);
-                            const S = this.meshTexList.get(h.components.url);
-                            C.type === "png" && (S ? S.find(P=>P === C.name) || S.push(C.url) : this.meshTexList.set(t, [C.name]))
+                        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]))
                         }
                         ),
-                        o(d)
+                        c(et)
                     }
-                    ).catch(h=>{
-                        logger.error(`[Engine] parse json file error,${h}`)
+                    ).catch($=>{
+                        d(`[Engine] parse json file error,${$}`)
                     }
                     )
                 }
-                ).catch(c=>{
-                    logger.error(`[Engine] ulrtransform error, cannot find resource in db,${c}`)
+                ).catch(j=>{
+                    d(`[Engine] ulrtransform error, cannot find resource in db,${j}`)
                 }
                 )
             }
         }
         )
     }
-    async parse(e, t) {
-        const r = [];
-        t.forEach(n=>{
-            this._setAnimationList(n.id, n.animations),
-            r.push(this.getParsedUrl(e, n.id, n.url)),
-            n.components.forEach(o=>{
-                o.units.forEach(a=>{
-                    r.push(this.getParsedUrl(e, a.name, a.url))
+    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))
                 }
                 )
             }
             )
         }
         ),
-        await Promise.all(r)
+        await Promise.all(o)
     }
-    _setAnimationList(e, t) {
-        t ? t.forEach(r=>{
-            this.aniPath.set(e + "_" + r.name, r.url)
+    _setAnimationList(e, i) {
+        i ? i.forEach(o=>{
+            this.aniPath.set(e + "_" + o.name, o.url)
         }
         ) : logger.error("[Engine] no animation list exist, please check config for details")
     }
     disposeContainer() {
-        this.containers.forEach((e,t)=>{
-            e.xReferenceCount < 1 && (this.enableShareTexture && e.textures.length > 0 && e.textures[0].xReferenceCount != null && (e.textures[0].xReferenceCount--,
-            e.textures = []),
-            e.dispose(),
-            this.containers.delete(t))
+        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 = []
+                }
+                e.push(o)
+            }
         }
         ),
-        this._sharedTex.forEach((e,t)=>{
-            e.xReferenceCount == 0 && (e.dispose(),
-            this._sharedTex.delete(t))
+        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)
+        }
+        ),
+        this._sharedTex.forEach((i,o)=>{
+            i.xReferenceCount == 0 && (i.dispose(),
+            this._sharedTex.delete(o))
         }
         )
     }
@@ -133,175 +171,172 @@ export default class XAvatarLoader {
     getMeshUrl(e) {
         return this.mshPath.get(e)
     }
-    _getSourceKey(e, t) {
-        return t && avatarSetting.lod[t] ? e + avatarSetting.lod[t].fileName.split(".")[0] : e
+    _getSourceKey(e, i) {
+        return i && avatarSetting.lod[i] ? e + avatarSetting.lod[i].fileName.split(".")[0] : e
     }
-    _getAnimPath(e, t) {
-        let r = this.aniPath.get(t + "_animations_" + t.split("_")[1]);
-        return r || (r = this.aniPath.get(t + "_" + e)),
-        r
+    _getAnimPath(e, i) {
+        let o = this.aniPath.get(i + "_animations_" + i.split("_")[1]);
+        return o || (o = this.aniPath.get(i + "_" + e)),
+        o
     }
-    load(e, t, r, n) {
-        return new Promise((o,a)=>{
-            this.loadGlb(e, t, r).then(s=>s ? o(s) : a("[Engine] container load failed")).catch(()=>a("[Engine] container load failed"))
-        }
-        )
+    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"))
     }
-    _searchAnimation(e, t) {
-        let r;
-        return this.containers.forEach((n,o)=>{
-            const a = t.split("_")[0];
-            o.indexOf(a) != -1 && o.indexOf(e) != -1 && (r = n)
+    _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)
         }
         ),
-        r
+        o
     }
-    loadAnimRes(e, t, r) {
-        return new Promise((n,o)=>{
-            const a = this._getAnimPath(t, r)
-              , s = getAnimationKey(t, r);
-            if (a && this.containers.get(a))
-                return n(this.containers.get(a));
-            if (a)
-                this._loadGlbFromBlob(e, s, a).then(l=>l.animationGroups.length == 0 ? (this.containers.delete(s),
-                l.dispose(),
-                Promise.reject("container does not contains animation data")) : n(l));
-            else
-                return o("no such url")
-        }
-        )
+    loadAnimRes(e, i, o) {
+        const s = this._getAnimPath(i, o)
+          , c = getAnimationKey(i, o);
+        return s && this.containers.get(s) ? Promise.resolve(this.containers.get(s)) : s ? this._loadGlbFromBlob(e, c, s).then(d=>d.animationGroups.length == 0 ? (this.containers.delete(c),
+        d.dispose(),
+        Promise.reject("container does not contains animation data")) : d) : Promise.reject("no such url")
     }
-    loadGlb(e, t, r) {
-        let n = this.getMeshUrl(this._getSourceKey(t, r));
-        return !n && this.fillEmptyLod && (r = 0,
-        n = this.getMeshUrl(this._getSourceKey(t, r))),
-        n && this.containers.get(n) ? Promise.resolve(this.containers.get(n)) : n ? this._enableIdb ? Promise.resolve(this._loadGlbFromBlob(e, this._getSourceKey(t, r), n)) : Promise.resolve(this._loadGlbFromUrl(e, this._getSourceKey(t, r), n)) : Promise.reject("no such url")
+    loadGlb(e, i, o) {
+        let s = this.getMeshUrl(this._getSourceKey(i, o));
+        return !s && this.fillEmptyLod && (o = 0,
+        s = this.getMeshUrl(this._getSourceKey(i, o))),
+        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")
     }
-    loadGltf(e, t, r, n) {
-        const o = this._getSourceKey(t, r || 0);
-        let a = this.getGltfPath(o);
-        return !a && this.fillEmptyLod && (a = this.getGltfPath(t)),
-        a && this.containers.get(a) ? Promise.resolve(this.containers.get(a)) : this._enableIdb ? this._loadGltfFromBlob(e, t, r, n) : a ? this._loadGltfFromUrl(e, t, a.replace(t + ".gltf", "")) : Promise.reject()
+    loadGltf(e, i, o, s) {
+        const c = this._getSourceKey(i, o || 0);
+        let d = this.getGltfPath(c);
+        return !d && this.fillEmptyLod && (d = this.getGltfPath(i)),
+        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()
     }
     loadSubsequence() {}
     loadVAT() {}
     getResourceName(e) {
         return this.meshTexList.get(e)
     }
-    _loadGltfFromUrl(e, t, r) {
-        return BABYLON.SceneLoader.LoadAssetContainerAsync(r, t + ".gltf", e.Scene, null, ".gltf")
+    _loadGltfFromUrl(e, i, o) {
+        return BABYLON.SceneLoader.LoadAssetContainerAsync(o, i + ".gltf", e.Scene, null, ".gltf")
     }
-    _loadGlbFromBlob(e, t, r) {
-        return new Promise((n,o)=>{
-            e.urlTransformer(r).then(a=>{
-                BABYLON.SceneLoader.LoadAssetContainerAsync("", a, e.Scene, null, ".glb").then(s=>{
-                    if (s) {
-                        if (this.enableShareTexture && s.textures.length > 0) {
-                            const l = t.indexOf("_lod") != -1 ? t.slice(0, -5) : t
-                              , u = this._sharedTex.get(l);
-                            u ? (s.meshes[1].material._albedoTexture = u,
-                            s.textures.forEach(c=>{
-                                c.dispose()
+    _loadGlbFromBlob(e, i, o) {
+        return e.urlTransformer(o).then(s=>BABYLON.SceneLoader.LoadAssetContainerAsync("", s, e.Scene, null, ".glb").then(c=>{
+            if (c) {
+                if (this.containers.get(o))
+                    return c.dispose(),
+                    this.containers.get(o);
+                if (c.addAllToScene(),
+                this.enableShareTexture && c.textures.length > 0) {
+                    const d = [];
+                    let _ = !1;
+                    c.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);
+                                $ ? (_ = !0,
+                                b.material._albedoTexture = $,
+                                d.push($),
+                                $._parentContainer = c,
+                                $.xReferenceCount++) : (this._sharedTex.set(j, k),
+                                c.textures[0].xReferenceCount = 1)
                             }
-                            ),
-                            s.textures = [u],
-                            u.xReferenceCount++) : (this._sharedTex.set(l, s.textures[0]),
-                            s.textures[0].xReferenceCount = 1)
-                        }
-                        return s.addAllToScene(),
-                        s.xReferenceCount = 0,
-                        s.meshes.forEach(l=>{
-                            l.setEnabled(!1)
                         }
-                        ),
-                        this.containers.set(r, s),
-                        n(s)
-                    } else
-                        o("glb file load failed")
-                }
-                )
-            }
-            )
-        }
-        )
-    }
-    _loadGlbFromUrl(e, t, r) {
-        return new Promise((n,o)=>{
-            BABYLON.SceneLoader.LoadAssetContainerAsync("", r, e.Scene, null, ".glb").then(a=>{
-                if (a) {
-                    if (a.addAllToScene(),
-                    a.meshes.forEach(s=>{
-                        s.setEnabled(!1)
                     }
                     ),
-                    this.enableShareTexture && a.textures.length > 0) {
-                        const s = t.indexOf("_lod") != -1 ? t.slice(0, -5) : t
-                          , l = this._sharedTex.get(s);
-                        l ? (a.meshes[1].material._albedoTexture = l,
-                        a.textures.forEach(u=>{
-                            u.dispose()
-                        }
-                        ),
-                        a.textures = [l],
-                        l.xReferenceCount++) : (this._sharedTex.set(s, a.textures[0]),
-                        a.textures[0].xReferenceCount = 1)
+                    _ && (c.textures.forEach(b=>{
+                        e.Scene.removeTexture(b),
+                        b.dispose()
                     }
-                    return a.xReferenceCount = 0,
-                    this.containers.set(r, a),
-                    n(a)
-                } else
-                    o("glb file load failed")
+                    ),
+                    c.textures = d)
+                }
+                return c.xReferenceCount = 0,
+                c.meshes.forEach(d=>{
+                    d.setEnabled(!1)
+                }
+                ),
+                this.containers.set(o, c),
+                Promise.resolve(c)
+            } else
+                return Promise.reject("glb file load failed")
+        }
+        ))
+    }
+    _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)
+        }
+        ),
+        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)
+                }
             }
-            )
         }
-        )
+        ),
+        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"))
     }
-    _loadGltfFromBlob(e, t, r, n) {
-        return new Promise((o,a)=>{
-            const s = [];
-            let l = this._getSourceKey(t, r)
-              , u = this.getGltfPath(l);
-            if (!u && this.fillEmptyLod && (r = 0,
-            l = this._getSourceKey(t, r),
-            u = this.getGltfPath(l)),
-            !u)
-                return a(`[Engine] gltf path incorrect ${l},cancel.`);
-            const c = this.mshPath.get(l + ".gltf");
-            if (!c)
-                return a("cannot find asset mshPath");
-            const h = this.binPath.get(l + ".bin");
-            if (!h)
-                return a("cannot find asset binPath");
-            if (!n) {
-                const _ = this.meshTexList.get(t);
-                if (!_ || _.length == 0)
-                    return a("cannot find texture");
-                n = _[0]
+    _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 f = this.texPath.get(n + ".png");
-            if (!f)
-                return a();
-            const d = this.texPath.get(n + "-astc.ktx");
-            if (!d)
-                return a();
-            s.push(this._blobMapping(e, c)),
-            s.push(this._blobMapping(e, h)),
-            s.push(this._blobMapping(e, f)),
-            s.push(this._blobMapping(e, d)),
-            Promise.all(s).then(()=>{
-                const _ = u.replace(l + ".gltf", "");
-                BABYLON.SceneLoader.LoadAssetContainerAsync(_, l + ".gltf", e.Scene, null, ".gltf").then(g=>{
-                    var v;
-                    this.containers.set(u, g),
-                    g.addAllToScene(),
-                    g.meshes.forEach(y=>{
-                        y.setEnabled(!1)
+            const _e = this.texPath.get(s + ".png");
+            if (!_e)
+                return d();
+            const et = this.texPath.get(s + "-astc.ktx");
+            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)
                     }
                     );
-                    const m = this._sharedTex.get(t);
-                    m ? ((v = g.meshes[1].material._albedoTexture) == null || v.dispose(),
-                    g.meshes[1].material._albedoTexture = m) : this._sharedTex.set(t, g.meshes[1].material._albedoTexture),
-                    o(g)
+                    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)
                 }
                 )
             }
@@ -309,10 +344,10 @@ export default class XAvatarLoader {
         }
         )
     }
-    _blobMapping(e, t) {
-        return new Promise((r,n)=>{
-            e.urlTransformer(t).then(o=>o ? (this._mappings.set(t, o),
-            r(t)) : n(`[Engine] url urlTransformer parse error ${t}`))
+    _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}`))
         }
         )
     }

+ 92 - 103
src/XAvatarManager.js

@@ -164,47 +164,35 @@ export default class XAvatarManager {
         this.characterMap.set(4, new Map),
         this.characterMap.set(5, new Map)
     }
-    loadAvatar({id: e, avatarType: t, priority: r, avatarManager: n, assets: o, status: a}) {
-        return new Promise((s,l)=>{
-            if (this.getAvatarById(e))
-                return l(new DuplicateAvatarIDError(`[Engine] cannot init avatar with the same id = ${e}`));
+    loadAvatar({id, avatarType, priority, avatarManager, assets, status}) {
+        return new Promise((resolve, reject)=>{
+            if (this.getAvatarById(id))
+                return reject(new DuplicateAvatarIDError(`[Engine] cannot init avatar with the same id = ${e}`));
             if (this.getAvatarNums() > this.maxAvatarNum)
-                return l(new ExceedMaxAvatarNumError(`[Engine] \u8D85\u51FA\u6700\u5927\u89D2\u8272\u9650\u5236 ${this.maxAvatarNum}`));
-            const u = new XAvatar({
-                id: e,
-                avatarType: t,
-                priority: r,
-                avatarManager: n,
-                assets: o,
-                status: a
-            });
-            this.registerAvatar(u);
-            if (r == 0)
-                this.setMainAvatar(u.id),
-                this.addAvatarToScene(u, 0).then(c=>(logger.debug(`[Engine] avatar ${u.id} has been added to scene`),
-                c ? (this._updateBillboardStatus(c, BillboardStatus.SHOW),
-                setTimeout(()=>{
-                    this.launchProcessLoadingLoop()
-                }
-                , this._delayTime),
-                s(c)) : (u.removeAvatarFromScene(),
-                l(new AvatarAssetLoadingError)))).catch(c=>(u.removeAvatarFromScene(),
-                l(new AvatarAssetLoadingError(c))));
-            else
-                return s(u)
+                return reject(new ExceedMaxAvatarNumError(`[Engine] \u8D85\u51FA\u6700\u5927\u89D2\u8272\u9650\u5236 ${this.maxAvatarNum}`));
 
-            // this.setMainAvatar(u.id),
-            // this.addAvatarToScene(u, 0).then(c=>(logger.debug(`[Engine] avatar ${u.id} has been added to scene`),
-            // c ? (this._updateBillboardStatus(c, BillboardStatus.SHOW),
-            // setTimeout(()=>{
-            //     this.launchProcessLoadingLoop()
-            // }
-            // , this._delayTime),
-            // s(c)) : (u.removeAvatarFromScene(),
-            // l(new AvatarAssetLoadingError)))).catch(c=>(u.removeAvatarFromScene(),
-            // l(new AvatarAssetLoadingError(c))));
-        }
-        )
+            const avatar = new XAvatar({ id, avatarType, priority, avatarManager, assets, status });
+            this.registerAvatar(avatar);
+
+            if (priority == 0)
+                this.setMainAvatar(avatar.id),
+                this.addAvatarToScene(avatar, 0).then(c=>(
+                    logger.debug(`[Engine] avatar ${avatar.id} has been added to scene`),
+                    c ? (
+                        this._updateBillboardStatus(c, BillboardStatus.SHOW),
+                        setTimeout(()=>{ this.launchProcessLoadingLoop() }, this._delayTime),
+                        resolve(c)
+                    ) : (
+                        avatar.removeAvatarFromScene(),
+                        reject(new AvatarAssetLoadingError)
+                    )
+                )).catch(c=>(
+                    avatar.removeAvatarFromScene(),
+                    reject(new AvatarAssetLoadingError(c))
+                ));
+            else
+                return resolve(avatar)
+        })
     }
     deleteAvatar(e) {
         return e.isRender ? (e.removeAvatarFromScene(),
@@ -550,7 +538,7 @@ export default class XAvatarManager {
         return new Promise((n,o)=>avatarLoader.load(this.sceneManager, t, r).then(a=>{
             if (a) {
                 const s = a.instantiateModelsToScene();
-                // 周恩光加 此时body_man缩放已经0.01
+                // zeg 此时body_man缩放已经0.01
                 console.log("body_man缩放", s.rootNodes[0]._children[0]._scaling)
                 a.xReferenceCount++;
                 const l = {
@@ -600,7 +588,7 @@ export default class XAvatarManager {
             if (a) {
                 this._clipContainerRes(a);
                 const s = a.meshes[1].clone(a.meshes[1].name, null);
-                // 周恩光加 装饰模型scale矫正
+                // zeg 装饰模型scale矫正
                 s.scaling = new BABYLON.Vector3(-0.01, 0.01, -0.01)
                 if (!s) {
                     logger.warn("[Engine] decoration does not exist!"),
@@ -632,79 +620,80 @@ export default class XAvatarManager {
     _getSourceKey(e, t) {
         return t && avatarSetting.lod[t] ? e + avatarSetting.lod[t].fileName.split(".")[0] : e
     }
-    addAvatarToScene(e, t) {
-        const r = Date.now();
-        return new Promise((n,o)=>{
-            this.loadBody(e.avatarType, e.avatarType, t).then(a=>{
-                // console.error(a.root._children[0]._scaling)
-                var s;
-                if (!a)
-                    return e.isInLoadingList = !1,
-                    o(new ContainerLoadingFailedError(`[Engine] avatar ${e.id} instanciates failed`));
-                if (e.attachBody(a),
-                a.animations.length > 0)
-                    return a.animations.forEach(l=>{
+    addAvatarToScene(xavatar, t) {
+        const startTime = Date.now();
+        return new Promise((resolve, reject)=>{
+            this.loadBody(xavatar.avatarType, xavatar.avatarType, t).then(modelData => {
+                if (!modelData) {
+                    xavatar.isInLoadingList = !1
+                    return reject(new ContainerLoadingFailedError(`[Engine] avatar ${xavatar.id} instanciates failed`));
+                }
+
+                xavatar.attachBody(modelData)
+                if (modelData.animations.length > 0) {
+                    modelData.animations.forEach(l=>{
                         l.stop()
+                    })
+                    xavatar.setAnimations(modelData.animations)
+                    xavatar.controller == null || xavatar.controller.playAnimation(xavatar.controller.onPlay, !0)
+                    xavatar.isRender = !0
+                    xavatar.isInLoadingList = !1
+                    xavatar.setAvatarVisible(!0)
+                    return resolve(xavatar);
+                }
+
+                this.loadAnimation(xavatar.avatarType, this._defaultAnims).then(l => {
+                    if (!l) {
+                        xavatar.removeAvatarFromScene()
+                        xavatar.isInLoadingList = !1
+                        return reject(new AvatarAnimationError);
                     }
-                    ),
-                    e.setAnimations(a.animations),
-                    (s = e.controller) == null || s.playAnimation(e.controller.onPlay, !0),
-                    e.isRender = !0,
-                    e.isInLoadingList = !1,
-                    e.setAvatarVisible(!0),
-                    n(e);
-                this.loadAnimation(e.avatarType, this._defaultAnims).then(l=>{
-                    if (!l)
-                        return e.removeAvatarFromScene(),
-                        e.isInLoadingList = !1,
-                        o(new AvatarAnimationError);
                     const u = [];
-                    e.clothesList.length > 0 && e.clothesList.forEach(c=>{
+                    xavatar.clothesList.length > 0 && xavatar.clothesList.forEach(c => {
                         u.push(this.loadDecoration(c.type, c.id, t))
-                    }
-                    ),
-                    Promise.all(u).then(c=>{
-                        var d, _, g, m;
+                    }),
+                    Promise.all(u).then(c => {
                         c.forEach(v=>{
-                            if (v && !v.isRender)
-                                e.attachDecoration(v);
-                            else
-                                return e.isInLoadingList = !1,
-                                e.removeAvatarFromScene(),
-                                o(new AvatarAssetLoadingError)
-                        }
-                        ),
-                        e.isRender = !0,
-                        (d = e.controller) == null || d.playAnimation(e.controller.onPlay, e.controller.loop),
-                        e.setAvatarVisible(!0);
+                            if (v && !v.isRender) {
+                                xavatar.attachDecoration(v);
+                            } else {
+                                xavatar.isInLoadingList = !1,
+                                xavatar.removeAvatarFromScene()
+                                return reject(new AvatarAssetLoadingError)
+                            }
+                        }),
+                        xavatar.isRender = !0,
+                        xavatar.controller == null || xavatar.controller.playAnimation(xavatar.controller.onPlay, xavatar.controller.loop),
+                        xavatar.setAvatarVisible(!0);
                         const h = avatarLoader.mshPath.get("meshes/ygb.glb")
                           , f = avatarLoader.matPath.get(avatarResources.ygb.mesh);
-                        h && f ? this.loadExtra(f, h).then(v=>{
-                            var y;
-                            e.isRender = !0,
-                            e.isInLoadingList = !1,
-                            e.distLevel = t,
-                            (y = this._sceneManager) == null || y.engineRunTimeStats.timeArray_addAvatarToScene.add(Date.now() - r),
-                            n(e)
+                        if(h && f) {
+                            this.loadExtra(f, h).then(v => {
+                                xavatar.isRender = !0,
+                                xavatar.isInLoadingList = !1,
+                                xavatar.distLevel = t,
+                                this._sceneManager == null || this._sceneManager.engineRunTimeStats.timeArray_addAvatarToScene.add(Date.now() - startTime),
+                                resolve(xavatar)
+                            })
+                        } else {
+                            xavatar.isRender = !0,
+                            xavatar.isInLoadingList = !1,
+                            xavatar.distLevel = t,
+                            this._sceneManager == null || this._sceneManager.engineRunTimeStats.timeArray_addAvatarToScene.add(Date.now() - startTime),
+                            resolve(xavatar)
                         }
-                        ) : (e.isRender = !0,
-                        e.isInLoadingList = !1,
-                        e.distLevel = t,
-                        (_ = this._sceneManager) == null || _.engineRunTimeStats.timeArray_addAvatarToScene.add(Date.now() - r),
-                        n(e)),
-                        (g = this._sceneManager) == null || g.lightComponent.setShadow(e),
-                        e.isInLoadingList = !1,
-                        e.distLevel = t,
-                        (m = this._sceneManager) == null || m.engineRunTimeStats.timeArray_addAvatarToScene.add(Date.now() - r),
-                        n(e)
+                        this._sceneManager == null || this._sceneManager.lightComponent.setShadow(xavatar),
+                        xavatar.isInLoadingList = !1,
+                        xavatar.distLevel = t,
+                        this._sceneManager == null || this._sceneManager.engineRunTimeStats.timeArray_addAvatarToScene.add(Date.now() - startTime),
+                        resolve(xavatar)
                     }
-                    ).catch(()=>o(new AvatarAssetLoadingError(`[Engine] avatar ${e.id} instanciates failed.`)))
+                    ).catch(()=>reject(new AvatarAssetLoadingError(`[Engine] avatar ${xavatar.id} instanciates failed.`)))
                 }
-                ).catch(()=>o(new AvatarAssetLoadingError(`[Engine] avatar ${e.id} instanciates failed.`)))
+                ).catch(()=>reject(new AvatarAssetLoadingError(`[Engine] avatar ${xavatar.id} instanciates failed.`)))
             }
-            ).catch(()=>o(new AvatarAssetLoadingError(`[Engine] avatar ${e.id} instanciates failed.`)))
-        }
-        )
+            ).catch(()=>reject(new AvatarAssetLoadingError(`[Engine] avatar ${xavatar.id} instanciates failed.`)))
+        })
     }
     loadExtra(e, t) {
         const r = avatarResources.ygb.name;

+ 0 - 222
src/XSequence.js

@@ -1,222 +0,0 @@
-import {http2} from "./Http2.js"
-import XSubSequence from "./XSubSequence.js"
-
-const DefaultUrlTransformer = async i=>typeof i != "string" ? (console.warn("url transformer error", i),
-i) : i.startsWith("blob:") ? i : http2.get({
-    url: i,
-    useIndexedDb: !0,
-    key: "url"
-});
-
-export default class XSequence {
-    constructor(e, t, r="test", n=DefaultUrlTransformer) {
-        E(this, "_scene");
-        E(this, "_name");
-        E(this, "_subSeqs");
-        E(this, "_animGroup");
-        E(this, "_targetSubSeqs");
-        E(this, "_abosoluteUrl");
-        E(this, "_rootDir");
-        E(this, "urlTransformer");
-        E(this, "init", async()=>new Promise(e=>{
-            this.urlTransformer(this._abosoluteUrl).then(t=>{
-                const r = new XMLHttpRequest;
-                r.open("get", t),
-                r.send(null),
-                r.onload = ()=>{
-                    if (r.status == 200) {
-                        const n = JSON.parse(r.responseText);
-                        this.load(n).then(()=>{
-                            e()
-                        }
-                        )
-                    }
-                }
-            }
-            )
-        }
-        ));
-        E(this, "getRootOfSubSeqs", ()=>{
-            const e = new Array;
-            return this._subSeqs.forEach(t=>{
-                e.push(t.root)
-            }
-            ),
-            e
-        }
-        );
-        E(this, "play", async(e=!0)=>new Promise(t=>{
-            this._animGroup.play(e),
-            e ? this._animGroup.onAnimationGroupLoopObservable.addOnce(()=>{
-                t()
-            }
-            ) : this._animGroup.onAnimationGroupEndObservable.addOnce(()=>{
-                t()
-            }
-            )
-        }
-        ));
-        E(this, "goToFrame", e=>{
-            this._animGroup.goToFrame(e)
-        }
-        );
-        E(this, "hide", ()=>{
-            this._subSeqs.forEach(e=>{
-                e.hide()
-            }
-            )
-        }
-        );
-        E(this, "show", ()=>{
-            this._subSeqs.forEach(e=>{
-                e.show()
-            }
-            )
-        }
-        );
-        E(this, "pause", ()=>{
-            this._animGroup.pause()
-        }
-        );
-        E(this, "reset", ()=>{
-            this._animGroup.reset()
-        }
-        );
-        this._scene = e,
-        this._abosoluteUrl = t,
-        this._rootDir = t.split("/").slice(0, -1).join("/") + "/",
-        this._name = r,
-        this._subSeqs = new Map,
-        this._animGroup = new BABYLON.AnimationGroup("Seq_" + r,e),
-        this._targetSubSeqs = new Map,
-        this._animGroup.onAnimationGroupPlayObservable.add(()=>{
-            this._subSeqs.forEach(o=>{
-                o.show()
-            }
-            )
-        }
-        ),
-        this._animGroup.onAnimationGroupEndObservable.add(()=>{
-            this._subSeqs.forEach(o=>{
-                o.hide()
-            }
-            )
-        }
-        ),
-        this.urlTransformer = n
-    }
-    get animGroup() {
-        return this._animGroup
-    }
-    serialize() {
-        const e = {};
-        return e.SubSequence = new Array,
-        e.TimeLine = new Array,
-        this._subSeqs.forEach(t=>{
-            const r = {
-                name: t.name,
-                uri: t.path
-            };
-            e.SubSequence.push(r);
-            const n = this._targetSubSeqs.get(t);
-            n && e.TimeLine.push({
-                frame: n == null ? void 0 : n.frame,
-                position: n.position,
-                rotation: n.rotation,
-                scaling: n.scaling,
-                name: t.name
-            })
-        }
-        ),
-        e
-    }
-    get isPlaying() {
-        return this._animGroup.isPlaying
-    }
-    get isStarted() {
-        return this._animGroup.isStarted
-    }
-    get loaded() {
-        let e = !0;
-        return this._subSeqs.forEach(t=>{
-            e = e && t.loaded
-        }
-        ),
-        e
-    }
-    dispose() {
-        this._subSeqs.forEach(e=>{
-            e.dispose()
-        }
-        ),
-        this.animGroup.dispose()
-    }
-    setFrame(e, t) {
-        const r = this._subSeqs.get(e);
-        if (r) {
-            const n = this._targetSubSeqs.get(r);
-            n && (n.frame = t),
-            n && this.update(r, n)
-        }
-    }
-    get name() {
-        return this._name
-    }
-    update(e, t) {
-        if (t) {
-            const r = {
-                frame: t.frame,
-                scaling: new BABYLON.Vector3(t.scaling[0],t.scaling[1],t.scaling[2]),
-                position: new BABYLON.Vector3(t.position[0],t.position[1],t.position[2]),
-                rotation: new BABYLON.Vector3(t.rotation[0] / 180 * Math.PI,t.rotation[1] / 180 * Math.PI,t.rotation[2] / 180 * Math.PI),
-                name: t.name
-            }
-              , n = this._subSeqs.get(r.name);
-            n && (n.setPositionVector(r.position),
-            n.setRotationVector(r.rotation),
-            n.setScalingVector(r.scaling),
-            n.setStartFrame(r.frame),
-            this._targetSubSeqs.set(n, t),
-            n.onSubSequenceTransformationChangeObservable.add(()=>{
-                const o = this._targetSubSeqs.get(n);
-                o && (o.position = [n.pos.x, n.pos.y, n.pos.z]),
-                o && (o.rotation = [n.rot.x, n.rot.y, n.rot.z]),
-                o && (o.scaling = [n.scal.x, n.scal.y, n.scal.z])
-            }
-            ))
-        }
-    }
-    load(e) {
-        return new Promise((t,r)=>{
-            const n = new Array
-              , o = e.SubSequence
-              , a = e.TimeLine;
-            for (const s of o) {
-                s.uri.indexOf("./") == 0 && (s.uri = s.uri.slice(2));
-                const l = new XSubSequence(this._scene,this._rootDir + s.uri,this.urlTransformer);
-                this._subSeqs.set(s.name, l),
-                n.push(l.init())
-            }
-            Promise.all(n).then(()=>{
-                a.forEach(s=>{
-                    const l = this._subSeqs.get(s.name);
-                    l && this.update(l, s)
-                }
-                ),
-                this._subSeqs.forEach(s=>{
-                    s.animGroup.targetedAnimations.forEach(l=>{
-                        this._animGroup.addTargetedAnimation(l.animation, l.target)
-                    }
-                    )
-                }
-                ),
-                t()
-            }
-            , ()=>{
-                r()
-            }
-            )
-        }
-        )
-    }
-}

+ 190 - 145
src/XverseAvatar.js

@@ -5,6 +5,7 @@ import AvatarGroup from "./enum/AvatarGroup.js"
 import MotionType from "./enum/MotionType.js"
 import Queue from "./Queue.js"
 import Logger from "./Logger.js"
+import CoreBroadcastType from "./enum/CoreBroadcastType.js"
 
 const logger = new Logger('xverse-avatar')
 export default class XverseAvatar extends EventEmitter {
@@ -31,144 +32,142 @@ export default class XverseAvatar extends EventEmitter {
         E(this, "_lastAnimTraceId", "");
         E(this, "statusSyncQueue", new Queue);
         E(this, "extraInfo", {});
-        E(this, "setPosition", e=>{
-            var t;
-            !this._room.signal.isUpdatedYUV || (t = this.xAvatar) == null || t.setPosition(positionPrecisionProtect(e))
-        }
-        );
-        E(this, "setRotation", e=>{
-            var t;
-            !this._room.signal.isUpdatedYUV || (t = this.xAvatar) == null || t.setRotation(rotationPrecisionProtect(e))
-        }
-        );
+
+        E(this, "setPosition", pos => {
+            !this._room.signal.isUpdatedYUV || this.xAvatar == null || this.xAvatar.setPosition(positionPrecisionProtect(pos))
+        });
+
+        E(this, "setRotation", rota => {
+            !this._room.signal.isUpdatedYUV || this.xAvatar == null || this.xAvatar.setRotation(rotationPrecisionProtect(rota))
+        });
+
         E(this, "stopAnimation", ()=>{
-            var e, t;
-            (t = (e = this.xAvatar) == null ? void 0 : e.controller) == null || t.stopAnimation()
-        }
-        );
-        E(this, "_playAnimation", async(e,t=!0,r=!1)=>{
-            var o;
-            if (!this._room.signal.isUpdatedYUV)
-                return;
+            (this.xAvatar == null ? void 0 : this.xAvatar.controller) == null || this.xAvatar.controller.stopAnimation()
+        });
+
+        E(this, "_playAnimation", async(animationName, isLoop=!0, r=!1)=>{
+            if (!this._room.signal.isUpdatedYUV) return;
+
             if (this.state !== "idle" && !r)
                 return logger.debug("_playAnimation", "state is not idle"),
                 Promise.resolve("_playAnimation, state is not idle");
-            const n = Date.now();
+
+            const startTime = Date.now();
             try {
-                if (!((o = this.xAvatar) != null && o.controller))
-                    return Promise.reject(new InternalError(`[avatar: ${this.userId}] Play animation failed: ${e}, no controller`));
+                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: e,
-                        startTime: n,
+                        tag: animationName,
+                        startTime,
                         value: 0,
                         metric: "playAnimationStart"
                     })
-                }
-                );
-                const a = util.uuid();
-                this._lastAnimTraceId = a,
-                await this.xAvatar.controller.playAnimation(e, t),
-                a === this._lastAnimTraceId && !this.isMoving && !t && e !== "Idle" && this.xAvatar.controller.playAnimation("Idle", t).catch(s=>{
+                });
+
+                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: e,
-                    startTime: n,
+                    tag: animationName,
+                    startTime,
                     extra: {
-                        loop: t
+                        loop: isLoop
                     },
                     metric: "playAnimationEnd"
                 })
-            } catch (a) {
-                return logger.error(`[avatar: ${this.userId}] Play animation failed: ${e}`, a),
+            } catch (err) {
+                return logger.error(`[avatar: ${this.userId}] Play animation failed: ${animationName}`, err),
                 this.isSelf && logger.infoAndReportMeasurement({
-                    tag: e,
-                    startTime: n,
+                    tag: animationName,
+                    startTime,
                     metric: "playAnimationEnd",
-                    error: a,
+                    error: err,
                     extra: {
-                        loop: t
+                        loop: isLoop
                     }
                 }),
-                Promise.reject(a)
-            }
-        }
-        );
-        E(this, "changeComponents", async e=>{
-            const {mode: t, endAnimation: r=""} = e || {}
-              , n = JSON.parse(JSON.stringify(e.avatarComponents));
-            let o = avatarComponentsValidate(n, this._avatarModel);
-            return !ChangeComponentsMode[t] && !o && (o = new ParamError(`changeComponents failed, mode: ${t} is invalid`)),
-            o ? (logger.error(o),
-            Promise.reject(o)) : this._changeComponents({
-                avatarComponents: n,
-                mode: t,
-                endAnimation: r
-            }).then(()=>{
-                this.isSelf && t !== ChangeComponentsMode.Preview && this.avatarComponentsSync(this.avatarComponents)
+                Promise.reject(err)
             }
-            )
-        }
-        );
-        E(this, "_changeComponents", async e=>{
-            var o;
-            const {avatarComponents: t=[], mode: r} = e || {}
-              , n = Date.now();
+        });
+
+        E(this, "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)
+            })
+        });
+
+        E(this, "_changeComponents", async data=>{
+            const {avatarComponents=[], mode} = data || {}
+              , startTime = Date.now();
+
             try {
-                if (!this.xAvatar)
-                    return Promise.reject(new InternalError("changeComponents failed, without instance: xAvatar"));
-                const a = await avatarComponentsModify(this._avatarModel, t)
+                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(e);
+
+                if (l.length === 0) return this.avatarComponents;
+
+                await this.beforeChangeComponentsHook(data);
                 for (const u of l) {
-                    const {id: c, type: h, url: f, suitComb: d} = u;
-                    s.push((o = this.xAvatar) == null ? void 0 : o.addComponent(c, h, f, d))
+                    const {id, type, url, suitComb} = u;
+                    s.push(this.xAvatar == null ? void 0 : this.xAvatar.addComponent(id, type, url, suitComb))
                 }
-                return await Promise.all(s),
+
+                await Promise.all(s)
                 this.emit("componentsChanged", {
                     components: this.avatarComponents,
-                    mode: r
-                }),
+                    mode
+                })
                 this.isSelf && logger.infoAndReportMeasurement({
                     tag: "changeComponents",
-                    startTime: n,
+                    startTime,
                     metric: "changeComponents",
                     extra: {
-                        inputComponents: t,
+                        inputComponents: avatarComponents,
                         finalComponents: this.avatarComponents,
-                        mode: ChangeComponentsMode[r]
+                        mode: ChangeComponentsMode[mode]
                     }
-                }),
-                this.avatarComponents
-            } catch (a) {
-                return this.isSelf && logger.infoAndReportMeasurement({
+                })
+                return this.avatarComponents
+
+            } catch (error) {
+                this.isSelf && logger.infoAndReportMeasurement({
                     tag: "changeComponents",
-                    startTime: n,
+                    startTime,
                     metric: "changeComponents",
-                    error: a,
+                    error,
                     extra: {
-                        inputComponents: t,
+                        inputComponents: avatarComponents,
                         finalComponents: this.avatarComponents,
-                        mode: ChangeComponentsMode[r]
+                        mode: ChangeComponentsMode[mode]
                     }
-                }),
-                Promise.reject(a)
+                })
+                return Promise.reject(error)
             }
-        }
-        );
+        });
+
         E(this, "avatarComponentsSync", e=>{
             e = e.map(t=>({
                 type: t.type,
                 id: t.id
             })),
             this._room.actionsHandler.avatarComponentsSync(e)
-        }
-        );
+        });
+
         E(this, "hide", ()=>{
             var e;
             if ((e = this.xAvatar) != null && e.hide())
@@ -178,8 +177,8 @@ export default class XverseAvatar extends EventEmitter {
                 return logger.warn(t),
                 Promise.reject(t)
             }
-        }
-        );
+        });
+
         E(this, "show", ()=>{
             var e;
             if ((e = this.xAvatar) != null && e.show())
@@ -189,9 +188,10 @@ export default class XverseAvatar extends EventEmitter {
                 return logger.warn(t),
                 Promise.reject(t)
             }
-        }
-        );
+        });
+
         E(this, "sayTimer");
+
         this._userId = e,
         this._room = r,
         this.isSelf = o || !1,
@@ -202,23 +202,27 @@ export default class XverseAvatar extends EventEmitter {
         this._room.modelManager.getAvatarModelList().then(s=>{
             const l = s.find(u=>u.id === n);
             l && (this._avatarModel = l)
-        }
-        )
+        })
     }
+
     get avatarId() {
         return this._avatarId
     }
+
     get isRender() {
         var e;
         return !!((e = this.xAvatar) != null && e.isRender)
     }
+
     get isHidden() {
         var e;
         return !!((e = this.xAvatar) != null && e.isHide)
     }
+
     get motionType() {
         return this._motionType
     }
+
     set motionType(e) {
         this._motionType = e
     }
@@ -226,113 +230,131 @@ export default class XverseAvatar extends EventEmitter {
         var e;
         return (e = this.xAvatar) == null ? void 0 : e.nickName
     }
+
     get words() {
         var e;
         return (e = this.xAvatar) == null ? void 0 : e.words
     }
+
     get isHost() {
         return this._isHost
     }
+
     get failed() {
         return this._failed
     }
+
     get scale() {
         var e;
         return (e = this.xAvatar) == null ? void 0 : e.scale
     }
+
     get animations() {
         var e;
         return !this.xAvatar || !this.xAvatar.controller ? [] : ((e = this.xAvatar) == null ? void 0 : e.getAvaliableAnimations()) || []
     }
+
     get position() {
         var e;
         return (e = this.xAvatar) == null ? void 0 : e.position
     }
+
     get rotation() {
         var e;
         return (e = this.xAvatar) == null ? void 0 : e.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"
     }
+
     get isRotating() {
         return this._isRotating
     }
+
     set isRotating(e) {
         this._isRotating = e,
         this.state = e ? "rotating" : "idle"
     }
+
     get withModel() {
         return this._withModel
     }
+
     get avatarComponents() {
         var e;
         return JSON.parse(JSON.stringify(((e = this.xAvatar) == null ? void 0 : e.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))
     }
-    setScale(e) {
-        var t;
-        (t = this.xAvatar) == null || t.setScale(e > 0 ? e : 1)
+
+    setScale(scaleNum) {
+        this.xAvatar == null || this.xAvatar.setScale(scaleNum > 0 ? scaleNum : 1)
     }
-    async playAnimation(e) {
-        const {animationName: t, loop: r, extra: n} = e || {};
+
+    async playAnimation(aniData) {
+        const {animationName, loop: isLoop, extra} = aniData || {};
         if (this.isSelf) {
             if (this.isMoving)
                 try {
                     await this.stopMoving()
-                } catch (a) {
-                    return logger.error(`stopMoving error before playAnimation ${t}`, a),
-                    Promise.reject(`stopMoving error before playAnimation ${t}`)
+                } catch (err) {
+                    return logger.error(`stopMoving error before playAnimation ${animationName}`, err),
+                    Promise.reject(`stopMoving error before playAnimation ${animationName}`)
                 }
-            const o = {
+            const data = {
                 info: {
                     userId: this.userId,
-                    animation: t,
-                    loop: r,
-                    extra: encodeURIComponent(n || "")
+                    animation: animationName,
+                    loop: isLoop,
+                    extra: encodeURIComponent(extra || "")
                 },
                 broadcastType: CoreBroadcastType.PlayAnimation
             };
-            this._room.avatarManager.broadcast.broadcast({
-                data: o
-            })
+            this._room.avatarManager.broadcast.broadcast({ data })
         }
         return this.emit("animationStart", {
-            animationName: t,
-            extra: safeDecodeURIComponent(n || "")
+            animationName,
+            extra: safeDecodeURIComponent(extra || "")
         }),
-        this._playAnimation(t, r).then(()=>{
+        this._playAnimation(animationName, isLoop).then(()=>{
             this.emit("animationEnd", {
-                animationName: t,
-                extra: safeDecodeURIComponent(n || "")
+                animationName,
+                extra: safeDecodeURIComponent(extra || "")
             })
-        }
-        )
+        })
     }
+
     async beforeChangeComponentsHook(e) {}
+
     turnTo(e) {
         if (this._room.viewMode === "observer") {
             this._room.sceneManager.cameraComponent.MainCamera.setTarget(ue4Position2Xverse(e.point));
@@ -342,9 +364,9 @@ export default class XverseAvatar extends EventEmitter {
             this.emit("viewChanged", {
                 extra: (e == null ? void 0 : e.extra) || ""
             })
-        }
-        )
+        })
     }
+
     async moveTo(e) {
         const {point: t, extra: r=""} = e || {};
         if (!this.position)
@@ -361,15 +383,19 @@ export default class XverseAvatar extends EventEmitter {
             extra: r
         })
     }
+
     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),
         !this.xAvatar) {
@@ -385,6 +411,7 @@ export default class XverseAvatar extends EventEmitter {
         }
         , t))
     }
+
     silent() {
         var e;
         if (!this.xAvatar) {
@@ -393,15 +420,18 @@ export default class XverseAvatar extends EventEmitter {
         }
         (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
         }
         )
     }
+
     setNickname(e) {
         return this._room.actionsHandler.setNickName(encodeURIComponent(e))
     }
+
     _setNickname(e) {
         var r, n;
         if (!e)
@@ -415,16 +445,19 @@ export default class XverseAvatar extends EventEmitter {
             scale: this.xAvatar.scale
         }))
     }
+
     _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)
     }
+
     setPickBoxScale(e=1) {
         return this.xAvatar ? (this.xAvatar.setPickBoxScale(e),
         !0) : (logger.error("setPickBoxScale failed, without instance: xAvatar"),
         !1)
     }
+
     transfer(e) {
         const {player: t, camera: r, areaName: n, attitude: o, pathName: a} = e;
         return this._room.actionsHandler.transfer({
@@ -437,39 +470,51 @@ export default class XverseAvatar extends EventEmitter {
             tag: "transfer"
         })
     }
+
     avatarLoadedHook() {}
     avatarStartMovingHook() {}
     avatarStopMovingHook() {}
+
     async statusSync(e) {
-        var t, r, n;
         try {
-            if ((t = e.event) != null && t.rotateEvent) {
-                const {angle: o, speed: a} = e.event.rotateEvent
-                  , s = this.motionType === MotionType.Run ? "Running" : "Walking";
-                this.rotation && (this.rotation.yaw = this.rotation.yaw % 360,
-                o.yaw - this.rotation.yaw > 180 && (o.yaw = 180 - o.yaw),
-                this.isRotating = !0,
-                await this.xAvatar.rotateTo(o, this.rotation, s).then(()=>{
-                    this._playAnimation("Idle", !0),
-                    this.isRotating = !1
-                }
-                ))
+            // 旋转
+            if (e.event != null && e.event.rotateEvent) 
+            {
+                const {angle, speed} = e.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 (e.event && (((r = e.event) == null ? void 0 : r.points.length) || 0) > 1 && !this.isSelf) {
-                this.isMoving = !0,
+
+            // 行走
+            if (e.event && ((e.event == null ? void 0 : e.event.points.length) || 0) > 1 && !this.isSelf)
+            {
+                this.isMoving = true,
                 e.playerState.attitude && (this._motionType = e.playerState.attitude);
-                const o = this.motionType === MotionType.Run ? "Running" : "Walking"
-                  , a = this._room.skin.routeList.find(l=>l.areaName === this._room.currentState.areaName)
-                  , s = ((a == null ? void 0 : a.step) || 7.5) * 30 * (25 / 30);
-                this.position && await this._move({
-                    start: this.position,
-                    end: e.event.points[e.event.points.length - 1],
-                    walkSpeed: s,
-                    moveAnimation: o,
-                    inter: (n = e.event) == null ? void 0 : n.points.slice(0, -1)
-                }).then(()=>{
-                    this.isMoving = !1
-                }
+
+                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: e.event.points[e.event.points.length - 1],
+                        walkSpeed,
+                        moveAnimation: moveAnimation,
+                        inter: e.event == null ? void 0 : e.event.points.slice(0, -1)
+                    }).then(()=>{
+                        this.isMoving = false
+                    })
                 )
             }
         } catch {

+ 226 - 191
src/XverseAvatarManager.js

@@ -10,6 +10,7 @@ import XverseAvatar from "./XverseAvatar.js"
 import MotionType from "./enum/MotionType.js"
 import TimeoutError from "./error/TimeoutError.js"
 import Logger from "./Logger.js"
+import QueueType from "./enum/QueueType.js"
 
 const logger = new Logger('xverse-avatar-manager')
 export default class XverseAvatarManager extends EventEmitter {
@@ -54,13 +55,14 @@ export default class XverseAvatarManager extends EventEmitter {
     showAll(e=!0) {
         this.xAvatarManager.showAll(e)
     }
+
     async init() {
         this.xAvatarManager = this._room.sceneManager.avatarComponent;
         try {
-            const e = await this._room.modelManager.getApplicationConfig()
-              , {avatars: t} = e;
-            if (t) {
-                await avatarLoader.parse(this._room.sceneManager, t);
+            const configList = await this._room.modelManager.getApplicationConfig()
+              , {avatars} = configList;
+            if (avatars) {
+                await avatarLoader.parse(this._room.sceneManager, avatars);
                 return
             }
             return Promise.reject("cannot find avatar config list")
@@ -69,247 +71,280 @@ export default class XverseAvatarManager extends EventEmitter {
             Promise.reject("avatar mananger init error!")
         }
     }
-    async handleAvatar(e) {
-        var r;
-        if (this._room.viewMode === "simple" || !this._room.joined || !e.newUserStates)
+
+    async handleAvatar(signal) {
+        if (this._room.viewMode === "simple" || !this._room.joined || !signal.newUserStates)
             return;
-        let t = e.newUserStates;
-        if (((r = this._room._userAvatar) == null ? void 0 : r.isMoving) && this._room._userAvatar.motionType === MotionType.Run) {
-            const n = t.filter(a=>a.userId === this._room.userId)
-              , o = t.filter(a=>a.userId !== this._room.userId).slice(0, 2);
-            t = n.concat(o)
+
+        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 (e.getStateType === GetStateTypes.Event) {
-            this.syncAvatarsLength = (t || []).length;
-            const n = this._room.avatars.filter(s=>s.group == AvatarGroup.User);
-            n.filter(s=>!(t != null && t.find(l=>l.userId == s.userId))).forEach(s=>{
-                this.removeAvatar(s.userId)
-            }
-            );
-            const a = t.filter(s=>!n.find(l=>l.userId == s.userId));
+
+        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(t)
+        this._handleAvatar(newUserStates)
     }
-    async _handleAvatar(e) {
-        e == null || e.forEach(t=>{
-            var n, o, a, s, l, u, c, h, f;
-            const r = this._room.userId === t.userId;
-            if (((n = t.event) == null ? void 0 : n.type) === SyncEventType.ET_RemoveVisitor) {
-                const d = (a = (o = t.event) == null ? void 0 : o.removeVisitorEvent) == null ? void 0 : a.removeVisitorEvent
-                  , _ = JSON.parse(safeDecodeURIComponent(((l = (s = t.event) == null ? void 0 : s.removeVisitorEvent) == null ? void 0 : l.extraInfo) || ""))
-                  , {code: g, msg: m} = _;
-                d === RemoveVisitorType.RVT_ChangeToObserver ? this._room.audienceViewModeHook() : d === RemoveVisitorType.RVT_MoveOutOfTheRoom && this._room.leave(),
-                this._room.emit("visitorStatusChanged", {
-                    code: g,
-                    msg: m
-                })
+
+    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 })
             }
-            if (t.event && [SyncEventType.Appear, SyncEventType.Reset].includes(t.event.type) || !t.event) {
-                let d = this.avatars.get(t.userId);
-                t.playerState.avatarId && (d == null ? void 0 : d.avatarId) !== t.playerState.avatarId && (d = void 0,this.removeAvatar(t.userId));
-                if (d) {
-                    if (d.disconnected && d.setConnectionStatus(!1),
-                    (u = t.event) != null && u.id && this._room.actionsHandler.confirmEvent(t.event.id),
-                    t.playerState.nickName && (d == null || d._setNickname(t.playerState.nickName)),
-                    t.playerState.avatarComponents && !d.isSelf && d.xAvatar) {
-                        const _ = safeParseComponents(t.playerState.avatarComponents);
-                        d._changeComponents({
-                            avatarComponents: _,
+
+            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,
                             mode: ChangeComponentsMode.Preview
                         })
                     }
                 } else {
-                    const {position: _, angle: g} = t.playerState.player
-                      , m = t.playerState.avatarId
-                      , v = t.playerState.prioritySync
-                      , y = safelyJsonParse(t.playerState.extra);
-                    if (!m)
-                        return;
-                    const b = safeParseComponents(t.playerState.avatarComponents)
-                      , T = safeDecodeURIComponent(t.playerState.nickName)
-                      , C = this.calculatePriority(t.userId, y);
+                    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);
+                      
                     this.addAvatar({
-                        userId: t.userId,
-                        isHost: t.playerState.isHost,
-                        nickname: T,
-                        avatarPosition: _,
-                        avatarRotation: g,
-                        avatarScale: t.playerState.avatarSize,
-                        avatarId: m,
-                        avatarComponents: t.playerState.person === Person.First ? [] : b,
-                        priority: C,
+                        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,
                         group: AvatarGroup.User,
-                        prioritySync: v,
-                        extraInfo: y
+                        prioritySync,
+                        extraInfo
                     }).then(()=>{
-                        var A;
-                        (A = t.event) != null && A.id && this._room.actionsHandler.confirmEvent(t.event.id),
-                        this.updateAvatarPositionAndRotation(t),
-                        r && (this.xAvatarManager.setMainAvatar(t.userId),
-                        this._room.emit("userAvatarLoaded"),
-                        logger.info("userAvatarLoaded"))
-                    }
-                    ).catch(A=>{
-                        r && (this.xAvatarManager.setMainAvatar(t.userId),
-                        this._room.emit("userAvatarFailed", {
-                            error: A
-                        }),
-                        logger.error("userAvatarFailed", A))
-                    }
-                    )
+                        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)
+                        )
+                    })
                 }
             }
-            if (t.event && SyncEventType.Disappear === t.event.type && ((c = t == null ? void 0 : t.event) != null && c.id && this._room.actionsHandler.confirmEvent(t.event.id),
-            this.removeAvatar(t.userId)),
-            t.event && [SyncEventType.Move, SyncEventType.ChangeRenderInfo].includes(t.event.type) || !t.event) {
-                (h = t == null ? void 0 : t.event) != null && h.id && this._room.actionsHandler.confirmEvent(t.event.id);
-                const d = this.avatars.get(t.userId);
-                d && d.withModel && !d.isLoading && this.updateAvatarPositionAndRotation(t)
+
+            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 (!r && ((f = t.event) == null ? void 0 : f.type) === SyncEventType.Rotate) {
-                const d = this.avatars.get(t.userId);
-                d.statusSyncQueue.append({
+
+            if (!isMainAvatar && state.event && state.event.type === SyncEventType.Rotate) {
+                const avatar = this.avatars.get(state.userId);
+                avatar.statusSyncQueue.append({
                     type: QueueType.Rotate,
-                    action: ()=>d.statusSync(t)
+                    action: () => avatar.statusSync(state)
                 })
             }
-        }
-        )
+        })
     }
+
     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
     }
-    updateAvatarPositionAndRotation(e) {
-        var t, r;
-        if ((t = e == null ? void 0 : e.playerState) != null && t.player) {
-            let {position: n, angle: o} = e.playerState.player;
-            const a = this.avatars.get(e.userId);
-            if (!a)
-                return;
-            if (n = positionPrecisionProtect(n),
-            o = rotationPrecisionProtect(o),
-            a.isSelf && !this._room.networkController.rtcp.workers.inPanoMode && (a.setPosition(n),
-            a.setRotation(o)),
-            e.event && (((r = e.event) == null ? void 0 : r.points.length) || 0) > 1 && !a.isSelf && a.statusSyncQueue.append({
+
+    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: ()=>a.statusSync(e)
-            }),
-            e.renderInfo && a.isSelf) {
-                const {isMoving: s, isRotating: l} = e.renderInfo;
+                action: () => avatar.statusSync(userState)
+            })
+
+            if (userState.renderInfo && avatar.isSelf) {
+                const {isMoving, isRotating} = userState.renderInfo;
                 this._updateAvatarMovingStatus({
-                    id: e.userId,
-                    isMoving: !!s,
-                    isRotating: !!l
+                    id: userState.userId,
+                    isMoving: !!isMoving,
+                    isRotating: !!isRotating
                 })
             }
         }
     }
-    async addAvatar(e) {
-        const {userId: t, isHost: r, avatarPosition: n, avatarId: o, avatarRotation: a, nickname: s, avatarComponents: l=[], priority: u, group: c=AvatarGroup.Npc, avatarScale: h=DEFAULT_AVATAR_SCALE, extraInfo: f, prioritySync: d} = e
-          , _ = t === this._room.userId;
-        let g = this.avatars.get(t);
-        if (g)
-        {
-            return Promise.resolve(g);
-        }
 
-        g = new XverseAvatarManager.subAvatar({
-            userId: t,
-            isHost: r,
-            isSelf: _,
+    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,
             room: this._room,
-            avatarComponents: l,
-            avatarId: o,
-            nickname: s,
-            group: c
+            avatarComponents,
+            avatarId,
+            nickname,
+            group
         });
-        this.avatars.set(t, g);
-        if (!g.withModel)
-            return g.isLoading = !1,
-            g.avatarLoadedHook(),
-            this._room.emit("avatarChanged", {
-                avatars: this._room.avatars
-            }),
-            g;
-        const v = (await this._room.modelManager.getAvatarModelList()).find(b=>b.id === o)
-          , y = Date.now();
-        if (!v)
-            return this._room.emit("avatarChanged", {
-                avatars: this._room.avatars
-            }),
-            this.avatars.delete(t),
-            Promise.reject(`no such avatar model with id: ${o}`);
+        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}`);
+        }
+
         try {
-            let b = await avatarComponentsModify(v, l);
+            let b = await avatarComponentsModify(avatarData, avatarComponents);
             b = b.filter(A=>A.type != "pendant");
-            const T = await avatarComponentsParser(v, b)
-              , C = await this.xAvatarManager.loadAvatar({
-                id: t,
-                avatarType: o,
-                priority: u,
+            
+            const assets = await avatarComponentsParser(avatarData, b)
+              , xAvatar = await this.xAvatarManager.loadAvatar({
+                id: userId,
+                avatarType: avatarId,
+                priority,
                 avatarManager: this.xAvatarManager,
-                assets: T,
+                assets,
                 status: {
-                    avatarPosition: n,
-                    avatarRotation: a,
-                    avatarScale: h
+                    avatarPosition,
+                    avatarRotation,
+                    avatarScale
                 }
             })._timeout(8e3, new TimeoutError("loadAvatar timeout(8s)"));
-            return C.setPickBoxScale(t === this._room.userId ? 0 : 1),
-            g.xAvatar = C,
-            g.setScale(h),
-            g.extraInfo = f,
-            g.priority = u,
-            g.isLoading = !1,
-            g.prioritySync = !!d,
-            g._playAnimation("Idle", !0, !0),
-            g.avatarLoadedHook(),
-            this._room.emit("avatarChanged", {
-                avatars: this._room.avatars
-            }),
-            s && g._setNickname(s),
-            t === this._room.userId && (logger.infoAndReportMeasurement({
-                metric: "avatarLoadDuration",
-                startTime: y,
-                group: "costs"
-            }),
-            logger.infoAndReportMeasurement({
-                metric: "avatarLoadAt",
-                startTime: this._room._startTime,
-                group: "costs"
-            })),
-            g
-        } catch (b) {
-            return g.isLoading = !1,
-            this._room.emit("avatarChanged", {
-                avatars: this._room.avatars
-            }),
-            logger.error(b),
-            Promise.reject(b)
+            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 && (
+                logger.infoAndReportMeasurement({
+                    metric: "avatarLoadDuration",
+                    startTime,
+                    group: "costs"
+                }),
+                logger.infoAndReportMeasurement({
+                    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)
         }
     }
-    removeAvatar(e, t=!1) {
-        const r = this.avatars.get(e);
-        if (!!r) {
-            if (r.removeWhenDisconnected || t) {
-                r.xAvatar && this.xAvatarManager.deleteAvatar(r.xAvatar),
-                this.avatars.delete(e),
+
+    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),
                 this._room.emit("avatarChanged", {
                     avatars: this._room.avatars
                 });
                 return
             }
-            r.setConnectionStatus(!0)
+            avatar.setConnectionStatus(!0)
         }
     }
+
     clearOtherUsers() {
         this.avatars.forEach(e=>{
             !e.isSelf && e.group === AvatarGroup.User && this.removeAvatar(e.userId)
         }
         )
     }
+
     async _updateAvatarMovingStatus(e) {
         const {id: t, isMoving: r, isRotating: n} = e
           , o = this.avatars.get(t);

+ 0 - 91
src/XverseEffect.js

@@ -1,91 +0,0 @@
-//const log$8 = new Logger("effectManager");
-import TimeoutError from "./error/TimeoutError.js"
-
-export default class XverseEffect extends EventEmitter {
-    constructor({id: e, jsonPath: t, type: r, room: n, scale: o=1}) {
-        super();
-        E(this, "_id");
-        E(this, "type");
-        E(this, "effect");
-        E(this, "avatarEffect");
-        E(this, "_room");
-        E(this, "_isLoading", !0);
-        E(this, "_failed", !1);
-        E(this, "_scale", 1);
-        this._room = n,
-        this._id = e,
-        this.type = r,
-        this._scale = o,
-        this.effect = e === "Rain" || e === "Boom" ? new XRain(this._room.scene,t,urlTransformer) : r === IEffectType.Sequence ? new XSequence(this._room.scene,t,"",urlTransformer) : new XSubSequence(this._room.scene,t,urlTransformer),
-        this.avatarEffect = new XSubSequence(this._room.scene,t,urlTransformer)
-    }
-    get failed() {
-        return this._failed
-    }
-    get position() {
-        if (this.type !== IEffectType.Sequence)
-            return this.effect.position
-    }
-    get rotation() {
-        if (this.type !== IEffectType.Sequence)
-            return this.effect.rotation
-    }
-    get isLoading() {
-        return this._isLoading
-    }
-    get id() {
-        return this._id
-    }
-    get name() {
-        return this.effect.name
-    }
-    get isPlaying() {
-        var e;
-        return !!((e = this.effect) != null && e.isPlaying)
-    }
-    async init() {
-        try {
-            await this.effect.init()._timeout(1e4, new TimeoutError("effect init timeout(10s)")),
-            this._isLoading = !1,
-            this._failed = !1
-        } catch (e) {
-            throw this._isLoading = !1,
-            this._failed = !0,
-            log$8.error(`effect: ${this.id} init error`, e),
-            e
-        }
-    }
-    play(e=!1) {
-        return new Promise((t,r)=>{
-            this.effect.play(e),
-            this.isPlaying ? t() : r(`play effect: ${this.name} failed`)
-        }
-        )
-    }
-    hide() {
-        return this.effect.hide()
-    }
-    show() {
-        return this.effect.show()
-    }
-    setRotation(e) {
-        var t;
-        return this.type === IEffectType.Sequence ? Promise.reject("setRotation failed, sequence unSuported") : (t = this.effect) == null ? void 0 : t.setRotation(e)
-    }
-    setPosition(e) {
-        var t;
-        return this.type === IEffectType.Sequence ? Promise.reject("setPosition failed, sequence unSuported") : (t = this.effect) == null ? void 0 : t.setPosition(e)
-    }
-    setScaling(e) {
-        var t;
-        return this.type === IEffectType.Sequence ? Promise.reject("setScaling failed, sequence unSuported") : (this._scale = e,
-        (t = this.effect) == null ? void 0 : t.setScaling({
-            x: e,
-            y: e,
-            z: e
-        }))
-    }
-    dispose() {
-        this.effect.dispose()
-    }
-}

+ 37 - 1
src/enum/Actions.js

@@ -33,6 +33,42 @@ var Actions = {
     RemoveVisitor:1022,
     GetUserWithAvatar:1023,
     GetNewUserState:1024,
-    SetSyncPolicy:1025
+    SetSyncPolicy:1025,
+
+    1:'Clicking',
+    6:'PlayCG',
+    7:'Back',
+    8:'ChangeRoom',
+    13:'ChangeSkin',
+    15:'Joystick',
+    18:'Transfer',
+    22:'GetOnVehicle',
+    23:'GetOffVehicle',
+    34:'StopMoving',
+    1e3:'UnaryActionLine',
+    1001:'Init',
+    1002:'Exit',
+    1003:'SetIFrameInfo',
+    1004:'GetNeighborPoints',
+    1005:'ReserveSeat',
+    1006:'GetReserveStatus',
+    1007:'ChangeNickname',
+    1008:'ChangeBitRateInfo',
+    1009:'Echo',
+    1010:'SetPlayerState',
+    1011:'TurnTo',
+    1012:'TurnToFace',
+    1013:'RotateTo',
+    1014:'Rotation',
+    1015:'CameraTurnTo',
+    1016:'ConfirmEvent',
+    1017:'Broadcast',
+    2e4:'NotifyActionLine',
+    1020:'AudienceChangeToVisitor',
+    1021:'VisitorChangeToAudience',
+    1022:'RemoveVisitor',
+    1023:'GetUserWithAvatar',
+    1024:'GetNewUserState',
+    1025:'SetSyncPolicy'
 }
 export default Actions

+ 5 - 0
src/enum/QueueType.js

@@ -0,0 +1,5 @@
+var QueueType = {
+    Move:"Move",
+    Rotate:"Rotate"
+}
+export default QueueType

+ 2 - 2
src/main.js

@@ -35,8 +35,8 @@ const l = async()=>{
             roomId: 'e629ef3e-022d-4e64-8654-703bb96410eb',
             userId: nickname,
             // wsServerUrl: 'wss://uat-eks.xverse.cn/ws',
-            wsServerUrl: "ws://localhost:6688/ws",
-            // wsServerUrl: "wss://meta-socket.4dage.com/ws",
+            // wsServerUrl: "ws://localhost:6688/ws",
+            wsServerUrl: "wss://meta-socket.4dage.com/ws",
             appId: "10016",
             token: " ",
             nickname: nickname,