import Actions from "./enum/Actions.js"
import {eventsManager} from "./EventsManager.js"
import util from "./util.js"
import Person from "./enum/Person.js"
import ClickType from "./enum/ClickType.js"
import Logger from "./Logger.js"

import Response from "./Response.js"
import { VDecoder } from "./h264Decoder/VDecoder.js";

import { SrsRTC } from "./srsRtc.js";
import { Connection } from "./connection.js";


const ossVideoDir = "https://laser-data.oss-cn-shenzhen.aliyuncs.com/new-video/720p/"
const walkVideoFrame = 29

window.currentFrame = null
const logger = new Logger('actions-handler')
const QueueActions = [Actions.Transfer, Actions.ChangeSkin, Actions.GetOnVehicle, Actions.GetOffVehicle];
export default class ActionsHandler {
    constructor(e) {
        this.currentActiveAction = null
        this.room = e

        //xst
        window.workerReady = false
        this.vDecoder = new VDecoder({   
            maxChip: 3,
          });
        window.vDecoder = this.vDecoder
        this.init()
    }

    init(){
        this.vDecoder.on('ready', () => {
            console.log("ready");
            window.workerReady = true
        })

        this.initSocket()
    }
    
    initSocket() {

        // const sdk = new SrsRTC();
        const testConfig = {
          sceneCode: "testApp",
          userId: "testUser",
          roomId: "8888",
        };
        const connection = new Connection(testConfig);
        
        // console.log("sdk", sdk);
        // console.log("sdk", connection);
        // const url = "webrtc://demo-kms.4dage.com/live/test1";
        // sdk.start(url);

        window.connection = connection


        
        window.connection.socket.on("getRoute", (pathArr) => {
            console.log("getRoute", pathArr);

            if(!pathArr) return
            
            let {anglePlus, dircNum} = window.room.sceneManager.correctCameraDirec()
            
            pathArr.forEach(point => {
                let ue4Pos = util.xversePosition2Ue4({x: -point.location.x, y: point.location.y, z: point.location.z})
                point.location = new BABYLON.Vector3(ue4Pos.x, ue4Pos.y, ue4Pos.z)
            })

            const walkSpeed = 1     // m/s
            const frameRate = 29    // fps

            let walkPoints = []
            let sumWalkFrame = 0
            let videoArr = []
            for(let i = 0; i < pathArr.length - 1; i++) {
                // 目前视频返回帧数到159条会停止
                if(sumWalkFrame + walkFrame > 159) break

                let point0 = new BABYLON.Vector3(pathArr[i].location.x, pathArr[i].location.y, pathArr[i].location.z)
                let point1 = new BABYLON.Vector3(pathArr[i+1].location.x, pathArr[i+1].location.y, pathArr[i+1].location.z)
                let distanceVec = point1.clone().subtract(point0)
                let distance = distanceVec.length() / 100   // m    
                let distancePerFrame = walkSpeed / frameRate    // m/帧     // walkVideoFrame
                let walkFrame = Math.round(distance / distancePerFrame)     // 帧
                let dir = distanceVec.normalize()

                videoArr.push( {
                    path: ossVideoDir + pathArr[i].id + "/" + pathArr[i].id + "_" + pathArr[i+1].id + "_" + dircNum,
                    frame: walkFrame
                })
                sumWalkFrame += walkFrame
                for(let currentFrame = 1; currentFrame <= walkFrame; currentFrame++) {
                    walkPoints.push(point0.add(dir.scale(distancePerFrame * 100 * currentFrame)))   // 单位转换成cm
                }
            }

            console.log("[Walk]::path", walkPoints)

            window.walkSettings = {
                "frameNum": sumWalkFrame,
                "walkPoints": walkPoints,
            }

            window.walking = true

            this.mutiFetchData({
                type: 'move',
                videoDataArr: videoArr
            })
        });
    }

    async avatarComponentsSync(e){
        const t = {
            action_type: Actions.SetPlayerState,
            set_player_state_action: {
                player_state: {
                    avatar_components: JSON.stringify(e)
                }
            }
        };
        this.sendData({
            data: t
        })
    }

    async sendData(e) {
        /*
        //console.log('发送数据：'+JSON.stringify(e))
        await this.beforeSend(e);
        const t = util.uuid();
        this.room.networkController.sendRtcData(le(oe({}, e.data), {
            trace_id: t,
            user_id: this.room.options.userId
        }));

        if (e.track === !1)
        {
            return Promise.resolve(null);
        }
        const {sampleRate: r=1, timeout: n=2e3, tag: o, data: a, special: s} = e;
        return eventsManager.track({
            timeout: n,
            traceId: t,
            event: a.action_type,
            tag: o,
            extra: a
        }, {
            special: s,
            sampleRate: r,
            noReport: this.room.viewMode === "serverless" || this.room.options.viewMode === "serverless"
        }).finally(()=>{
            QueueActions.includes(e.data.action_type) && (this.currentActiveAction = void 0)
        }
        )
        */
    }

    //async sendData(e) {
        //console.log('发送数据：'+JSON.stringify(e))
        
        //旋转
        //window.room.sceneManager.scene.activeCamera.rotation.y

        //心跳：要去掉

        //邻居点：要去掉

        //漫游
        //人物所在位置和角度，相机的位置和角度，相机的目标点，点击的坐标
    //}

    async beforeSend(e) {
        var o;
        const t = (o = this.room._userAvatar) == null ? void 0 : o.isMoving
          , r = e.data.action_type;
        if (QueueActions.includes(r)) {
            if (this.currentActiveAction)
                return logger.error(`${Actions[this.currentActiveAction]} still pending, reject ${Actions[r]}`),
                Promise.reject(new FrequencyLimitError(`${Actions[r]} action request frequency limit`));
            this.currentActiveAction = r
        }
        if (t && QueueActions.includes(e.data.action_type))
            try {
                await this.stopMoving()
            } catch (a) {
                this.currentActiveAction = void 0,
                logger.error("before action stopMoving failed", a)
            }
    }
    async moveTo(e) {

        // 镜头矫正
        let {anglePlus, dircNum} = window.room.sceneManager.correctCameraDirec()
        let anglePlusFrame = Math.floor(anglePlus / (Math.PI/30))
        anglePlus = anglePlusFrame * (Math.PI/30)

        if(Math.abs(anglePlus) > 0.0001) {
            window.moveCallBack = {
                func: this.moveTo.bind(this),
                args: [e]
            }
            window.rotateCallBack = {
                func: this.rotate.bind(this),
                args: [{type: 'rotate', angle: Math.PI/30 * Math.sign(anglePlus)}],
                frame: anglePlusFrame,
                currentFrame: 0,
            }
            this.rotate({type: 'rotate', angle: Math.PI/30 * Math.sign(anglePlus)})

            return
        }


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

        let player = window.room.sceneManager.avatarComponent._mainUser

        let closestPoint = window.room.sceneManager.getClosestPointData(t)
        let closestPointSelf = window.room.sceneManager.getClosestPointData(player.position)

        console.log("[Walk]::from", closestPointSelf.position0, ":to", closestPoint.position0)
        window.connection.socket.emit("getRoute", {
            sceneCode: "testApp",
            userId: "testUser",
            roomId: "8888",
            s_location: {
                x: closestPointSelf.position0.x,
                y: closestPointSelf.position0.y,
                z: closestPointSelf.position0.z,
            },
            e_location: {
                x: closestPoint.position0.x,
                y: closestPoint.position0.y,
                z: closestPoint.position0.z,
            },
        });


        // if(this.walkHandle) clearInterval(this.walkHandle)

        // // window.room.moveTo(t)
        // let currentFrame = 0
        // this.walkHandle = setInterval(() => {
        //     currentFrame++
        //     let targetPos = {
        //         "x": player.position.x + distanceVec.x / frameNum,
        //         "y": player.position.y + distanceVec.y / frameNum,
        //         "z": player.position.z + distanceVec.z / frameNum
        //     }
        //     if(currentFrame < frameNum) {
        //         window.room.moveTo({
        //             position: targetPos, 
        //             isEnd: false
        //         })
        //     } else {
        //         window.room.moveTo({
        //             position: targetPos, 
        //             isEnd: true
        //         })
        //         clearInterval(this.walkHandle)
        //     }
        // }, 1000 / fps)

        // let date = new Date()
        // console.error(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds())
        
        // console.error(closestPointSelf.id)

        // return this.sendData({
        //     data: o
        // })
    }
    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 = {
            data: {
                action_type: Actions.Transfer,
                transfer_action: {
                    render_type: t,
                    player: r,
                    camera: n,
                    areaName: o,
                    attitude: a,
                    pathName: s,
                    person: {
                        type: l
                    },
                    noMedia: u,
                    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;
        return this.transfer({
            renderType: t,
            player: r,
            camera: n,
            areaName: o,
            attitude: a,
            pathName: s,
            tag: "changeToRotationVideo"
        })
    }
    requestPanorama(e, noMedia, timeout) {
        const {camera: camera, player: player, areaName: areaName, attitude: attitude, pathName: pathName, tag: tag} = e;
        return this.transfer({
            renderType: RenderType.ClientRotationPano,
            player: player,
            camera: camera,
            person: Person.First,
            areaName: areaName,
            attitude: attitude,
            pathName: pathName,
            noMedia: noMedia,
            timeout: timeout,
            tag: tag || "requestPanorama",
            special: !noMedia
        })
    }
    setMotionType(e) {
        return this.transfer({
            attitude: e,
            tag: "setMotionType"
        })
    }
    setNickName(e) {
        const t = {
            action_type: Actions.ChangeNickname,
            change_nickname_action: {
                nickname: e
            }
        };
        return this.sendData({
            data: t
        })
    }
    getReserveSeat({routeId: e, name: t}) {
        const r = {
            action_type: Actions.ReserveSeat,
            reserve_seat_action: {
                route_id: e,
                name: t
            }
        };
        return this.sendData({
            data: r
        })
    }
    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
            }
        };
        return this.sendData({
            data: n,
            timeout: 2e3
        }).then(o=>o.reserveDetail)
    }
    stopMoving() {
        const e = {
            action_type: Actions.StopMoving,
            stop_move_action: {}
        };
        return this.sendData({
            data: e
        })
    }
    getOnVehicle({routeId: e, name: t, camera: r}) {
        const n = {
            action_type: Actions.GetOnVehicle,
            get_on_vehicle_action: {
                route_id: e,
                name: t,
                camera: r
            }
        };
        return this.sendData({
            data: n
        })
    }
    getOffVehicle({renderType: e, player: t, camera: r}) {
        const n = {
            action_type: Actions.GetOffVehicle,
            get_off_vehicle_action: {
                render_type: e,
                player: t,
                camera: r
            }
        };
        return this.sendData({
            data: n
        })
    }
    confirmEvent(e) {
        const t = {
            action_type: Actions.ConfirmEvent,
            confirm_event_action: {
                id: e
            }
        };
        return this.sendData({
            data: t,
            track: !1
        })
    }
    echo(e) {
        const t = {
            action_type: Actions.Echo,
            echo_msg: {
                echoMsg: e
            }
        };
        return this.sendData({
            data: t,
            track: !1
        })
    }
    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];
        if (!m) {
            const y = `skin ${r} is invalid`;
            return logger.error(y),
            Promise.reject(new ParamError(y))
        }
        const v = {
            action_type: Actions.ChangeSkin,
            change_skin_action: {
                skinID: r,
                mode: n === ChangeMode.Preview ? ChangeMode.Preview : ChangeMode.Confirm,
                skin_data_version: r + m.versionId,
                landing_type: o,
                landing_point: a,
                landing_camera: s,
                render_wrapper: {
                    render_type: l
                },
                areaName: u,
                attitude: c,
                noMedia: d,
                person: f,
                pathName: h,
                roomTypeId: g
            }
        };
        return this.sendData({
            data: v,
            timeout: _ || 6e3,
            special: t
        }).then(async y=>{
            if (l === RenderType.ClientRotationPano && y) {
                const b = await this.room.modelManager.findRoute(r, h)
                  , {camera: T} = util.getRandomItem(b.birthPointList) || {};
                await this.room.panorama.handleReceivePanorama(y, T)
            }
            return this.handleChangeSkin(e)
        }
        ).catch(y=>d ? this.handleChangeSkin(e) : Promise.reject(y))
    }
    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(),
        this.room.engineProxy._updateSkinAssets(t).then(()=>{
            this.room.sceneManager.staticmeshComponent.getCgMesh().hide(),
            this.room.sceneManager.cameraComponent.switchToMainCamera(),
            this.room.pathManager.currentArea = o,
            logger.info("changeSkin _updateSkinAssets susccss"),
            this.room.updateCurrentNetworkOptions({
                pathName: s,
                attitude: a,
                areaName: o
            }),
            this.room.skinChangedHook(),
            this.room.emit("skinChanged", {
                skin: {
                    id: t
                },
                mode: r
            }),
            n === RenderType.ClientRotationPano && this.room.sceneManager.cameraComponent.allowMainCameraController()
        }
        )
    }

/***********************************************************************xst****************************************************************/
    /*
    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
            }
        };

        //console.log('发送数据rotate：'+JSON.stringify(r.rotation_action))
        this.sendData({
            data: r,
            sampleRate: .02
        })
    }
    */
    
    //zeg
    rotate({type: type, angle: angle}) {
        //camera的position，angle
        //起始和结束的帧

        let endRotation = util.xverseRotation2Ue4(window.room.sceneManager.cameraComponent.mainCamera.rotation).yaw
        endRotation = (endRotation % 360 + 360) % 360

        // todo 矫正
        let sfns = Math.round((endRotation + 180)/6)        // 仅视频贴图偏移矫正180度
        endRotation += angle/Math.PI*180
        endRotation = (endRotation % 360 + 360) % 360

        let efns = Math.round((endRotation + 180)/6)
        
        if(window.currentFrame == null){
            window.currentFrame = efns
        }
        else if(window.currentFrame != efns){
            window.currentFrame = efns
        }
        else if(window.currentFrame == efns){
            return
        }
        
        // 起始帧不需要传入
        if(efns>sfns) sfns = (sfns + 1 + 60) % 60
        if(efns<sfns) sfns = (sfns - 1 + 60) % 60
        efns = sfns // (efns + 60) % 60         // 目前一帧一帧跳，防止漂移和跨0问题
        // console.error(angle/Math.PI*180, endRotation, efns, sfns)

        window.rotating = true      // 标记旋转中
        window.rotateFrame = efns - sfns   // 旋转帧数
        window.camera_endRotation = endRotation
        window.star_angle = angle
        

        let player = window.room.sceneManager.avatarComponent._mainUser
        let closestPointSelf = window.room.sceneManager.getClosestPointData(player.position)

        console.log('取帧：'+sfns+','+efns);
        this.fetchData({
            type: type,
            path: ossVideoDir + closestPointSelf.id + "/" + closestPointSelf.id,
            sFrame: sfns,
            eFrame: efns
        })
        
        if(typeof(window.star_angle) == 'undefined'){
            return
        }
        this.room.sceneManager.materialComponent.initreceveFrames()
        // this.room.doRotate()
        //window.room.sceneManager.cameraComponent.mainCamera.rotation.y += angle
        //window.room.sceneManager.cameraComponent.setCameraPose(cameraState)
    }
    /*
    rotate({type: type, angle: angle}) {
        let endRotation = window.room.sceneManager.cameraComponent.mainCamera.rotation.y
        if(endRotation<0){
            endRotation += 2*Math.PI
        }
        else if(endRotation>2*Math.PI){
            endRotation -= 2*Math.PI
        }
        
        let sfns = Math.round(endRotation/Math.PI * 180 /6)
        //每6°一帧
        for(let i=0;i<60;++i){
            if(Math.abs(Math.abs(angle) - i/60 * 2 * Math.PI)<0.01){
                //找到了
                endRotation += angle
                break;
            }
        }
        let efns = Math.round(endRotation/Math.PI * 180 /6)
        console.log('取帧：'+sfns+','+efns);
        this.fetchData({
            type:type,
            sFrame:sfns,
            eFrame:efns
        })

        this.room.sceneManager.materialComponent.initreceveFrames()
 
        // this.room.sceneManager.cameraComponent.mainCamera.rotation.y = endRotation
        // window.room.sceneManager.cameraComponent._cameraPose.rotation._y = endRotation
        // window.room.sceneManager.cameraComponent.mainCamera.rotation.y=endRotation
        let response = JSON.parse(JSON.stringify(Response))
        response.signal.newUserStates[0].playerState.player.position.x = this.room.avatarManager.avatars.get(nickname).position.x
        response.signal.newUserStates[0].playerState.player.position.y = this.room.avatarManager.avatars.get(nickname).position.y
        response.signal.newUserStates[0].playerState.player.position.z = this.room.avatarManager.avatars.get(nickname).position.z

        response.signal.newUserStates[0].playerState.player.angle.pitch = this.room.avatarManager.avatars.get(nickname).rotation.pitch
        response.signal.newUserStates[0].playerState.player.angle.yaw = this.room.avatarManager.avatars.get(nickname).rotation.yaw
        response.signal.newUserStates[0].playerState.player.angle.roll = this.room.avatarManager.avatars.get(nickname).rotation.roll

        response.signal.newUserStates[0].playerState.camera.position = 
        response.signal.newUserStates[0].playerState.camera.angle = 

        response.signal.newUserStates[0].playerState.cameraCenter.x = this.room.avatarManager.avatars.get(nickname).position.x
        response.signal.newUserStates[0].playerState.cameraCenter.y = this.room.avatarManager.avatars.get(nickname).position.y
        response.signal.newUserStates[0].playerState.cameraCenter.z = this.room.avatarManager.avatars.get(nickname).position.z
 
    }
    */

    fetchData({type, path, sFrame: sfns, eFrame: efns}){
        // alert(path)
        if(window.workerReady){
            this.vDecoder.fetch({
                // path: "https://laser-data.oss-cn-shenzhen.aliyuncs.com/test-video/res/720p",
                path: path,
                // range: [sfns, efns],
                range: sfns == efns ? [efns] : [sfns, efns],
            });
        }
        else{
            console.error('还没准备好')
        }
    }

    mutiFetchData({type, videoDataArr}){
        console.log("[Walk]::videoData", videoDataArr)
        if(window.workerReady){
            // https://laser-data.oss-cn-shenzhen.aliyuncs.com/test-video/optest/0/0_1_0/
            let sendData = []
            // let videoPathArr = [
            //     "https://laser-data.oss-cn-shenzhen.aliyuncs.com/test-video/1011",
            //     "https://laser-data.oss-cn-shenzhen.aliyuncs.com/test-video/1",
            // ]
            videoDataArr.forEach(data => {
                for(let i = 0; i < data.frame; i++) {
                    sendData.push({
                        path: data.path,
                        frame: i,
                    })
                }
            })
            this.vDecoder.mutiFetch(sendData);
        }
        else{
            console.error('还没准备好')
        }
    }

/*******************************************************************************************************************************************/

    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
            }
        };
        return this.sendData({
            data: o,
            timeout: r
        })
    }
    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
            }
        };

        console.log('发送数据rotateTo：'+JSON.stringify(o.rotate_to_action))

        return this.sendData({
            data: o
        })
    }
    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 = {
            action_type: Actions.Broadcast,
            broadcast_action: {
                data: JSON.stringify(t),
                user_id: this.room.options.userId,
                msgType: r
            }
        };
        return Array.isArray(n) && r === MessageHandleType.MHT_CustomTargetSync && (o.broadcast_action.target_user_ids = n),
        this.room.actionsHandler.sendData({
            data: o,
            tag: t.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
            }
        };
        return this.sendData({
            data: o
        }).then(a=>a.nps)
    }
    playCG(e) {
        const t = {
            action_type: Actions.PlayCG,
            play_cg_action: {
                cg_name: e
            }
        };
        return this.sendData({
            data: t
        })
    }
    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
            }
        };
        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]
                }
            }
        };
        return logger.debug("send data: visitor to audience"),
        this.sendData({
            data: c
        })
    }
    removeVisitor(e) {
        const {removeType: t, userIDList: r, extraInfo: n=""} = e
          , o = {
            action_type: Actions.RemoveVisitor,
            removeVisitorAction: {
                removeVisitorEvent: t,
                userIDList: r,
                extraInfo: encodeURIComponent(n)
            }
        };
        return logger.debug("send data: remove visitor"),
        this.sendData({
            data: o
        })
    }
    getUserWithAvatar(e, t) {
        const r = {
            action_type: Actions.GetUserWithAvatar,
            getUserWithAvatarAction: {
                userType: e,
                roomID: t
            }
        };
        return logger.debug("send data: get user with avatar"),
        this.sendData({
            data: r
        }).then(n=>n.userWithAvatarList)
    }
    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
        };
        return this.sendData({
            data: a,
            track: !1
        })
    }
}