zhouenguang 3 роки тому
батько
коміт
7a8e901daa
3 змінених файлів з 463 додано та 390 видалено
  1. 337 288
      src/ActionsHandler.js
  2. 10 10
      src/ModelManager.js
  3. 116 92
      src/XverseAvatarManager.js

+ 337 - 288
src/ActionsHandler.js

@@ -8,27 +8,30 @@ 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) {
+    async sendData(actionData) 
+    {
+        console.error("[Action]", Actions[actionData.data.action_type])
+
         await this.beforeSend(actionData);
         const traceId = util.uuid();
         this.room.networkController.sendRtcData(le(oe({}, actionData.data), {
@@ -40,6 +43,7 @@ export default class ActionsHandler {
         {
             return Promise.resolve(null);
         }
+        
         const { sampleRate=1, timeout=2e3, tag, data, special } = actionData;
         return eventsManager.track({
             timeout,
@@ -56,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;
@@ -74,182 +79,210 @@ 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];
@@ -292,7 +325,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(),
@@ -317,205 +352,219 @@ 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
-            }
-        };
+
+    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
-            }
-        };
+
+    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
         })
     }

+ 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;

+ 116 - 92
src/XverseAvatarManager.js

@@ -55,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")
@@ -70,114 +71,137 @@ 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 == null || newUserStates.forEach(state=>{
+
+            const isMainAvatar = this._room.userId === state.userId;
+
+            if ((state.event != null && state.event.type) === SyncEventType.ET_RemoveVisitor) 
+            {
+                const removeVisitorEvent = state.event != null && state.event.removeVisitorEvent
+                const event =  removeVisitorEvent!= null && removeVisitorEvent.removeVisitorEvent
+                  , extraInfo = JSON.parse(safeDecodeURIComponent((removeVisitorEvent != null && removeVisitorEvent.extraInfo) || ""))
+                  , { code, msg } = extraInfo;
+
+                  event === RemoveVisitorType.RVT_ChangeToObserver 
+                    ? this._room.audienceViewModeHook() 
+                    : event === RemoveVisitorType.RVT_MoveOutOfTheRoom && this._room.leave()
+
+                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 != null && avatar.avatarId !== state.playerState.avatarId) {
+                    avatar = void 0
+                    this.removeAvatar(state.userId)
+                }
+
+                if (avatar) {
+                    if (avatar.disconnected && avatar.setConnectionStatus(!1),
+                    state.event != null && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id),
+                    state.playerState.nickName && (avatar == null || avatar._setNickname(state.playerState.nickName)),
+                    state.playerState.avatarComponents && !avatar.isSelf && avatar.xAvatar) {
+                        const avatarComponents = safeParseComponents(state.playerState.avatarComponents);
+                        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 != null && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id),
+                        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)
+                this.removeAvatar(state.userId)
+            }
+
+            if (state.event && [SyncEventType.Move, SyncEventType.ChangeRenderInfo].includes(state.event.type) || !state.event) {
+                state.event != null && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id);
+                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 != null && 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