gemercheung 3 سال پیش
والد
کامیت
4682860824
5فایلهای تغییر یافته به همراه379 افزوده شده و 335 حذف شده
  1. 4 1
      src/get-router/get-router.service.ts
  2. 166 171
      src/move/move.service.ts
  3. 3 0
      src/rotate/rotate.service.ts
  4. 7 8
      src/scene/scene.d.ts
  5. 199 155
      src/scene/scene.service.ts

+ 4 - 1
src/get-router/get-router.service.ts

@@ -114,6 +114,9 @@ export class GetRouterService implements OnModuleInit {
         // );
         // const item = JSON.parse(itemRes);
         const item = this.breakPointInfo[neighPointId];
+        if (this.existList(item, closeList) != -1) {
+          continue;
+        }
         item.breakPointId = neighPointId;
         //g 到父节点的位置
         const g =
@@ -121,7 +124,7 @@ export class GetRouterService implements OnModuleInit {
           this.getDistance(currentPoint.position, item.position);
         if (this.existList(item, openList) == -1) {
           //如果不在开启列表中
-          item['H'] = 0;
+          item['H'] = this.getDistance(endPoint.position, item.position);
           item['G'] = g;
           item['F'] = item.H + item.G;
           item['parent'] = currentPoint;

+ 166 - 171
src/move/move.service.ts

@@ -12,6 +12,24 @@ import { RotateService } from 'src/rotate/rotate.service';
 // import * as  BreakPointIds from '../../ws/points-BreakPointId.json';
 // import { SceneService } from 'src/scene/scene.service';
 
+const seqExeAsyncFn = (asyncFn) => {
+  let runPromise = null;
+  return function seq(...args) {
+    if (!runPromise) {
+      //debugger;
+      runPromise = asyncFn.apply(this, args);
+      runPromise.then((data) => {
+        //debugger;
+        // console.log('seq result', data);
+      });
+      runPromise.then(() => (runPromise = null));
+      return runPromise;
+    } else {
+      return runPromise.then(() => seq.apply(this, args));
+    }
+  };
+};
+
 @Injectable()
 export class MoveService implements OnModuleInit {
   constructor(
@@ -173,10 +191,11 @@ export class MoveService implements OnModuleInit {
 
       const appId = user.appId;
       const path = pathArray || [100, 101, 102]; //需要计算路径
-      let angle = user.camera.angle.yaw % 45; //纠正需要
+      const angle = user.camera.angle.yaw % 45; //纠正需要
       const replys = [];
       const traceIds = [];
       traceIds.push(traceId);
+      /*
       //纠正,旋转传到缓存里
       const checkReplys = [];
       // console.log('矫正: ' + angle + ' 度');
@@ -216,6 +235,13 @@ export class MoveService implements OnModuleInit {
           checkReplys.push(reply);
         }
       }
+      */
+      const checkReplys = await this.modeifyCameraAngle(
+        angle,
+        userId,
+        traceId,
+        actionType,
+      );
       //replys['P' + user.breakPointId + 'T' + user.breakPointId] = checkReplys;
       replys.push(checkReplys);
       if (checkReplys.length > 0) {
@@ -249,23 +275,6 @@ export class MoveService implements OnModuleInit {
           return replys;
         }
         const moveFrames = JSON.parse(moveFramesRes);
-        //读redis里的数据
-        const startBreakPointRes = await this.cacheService.get(
-          'breakpoints:app_id:' +
-            appId +
-            ':break_point_id:' +
-            start_break_point_id,
-        );
-
-        const startBreakPoint = JSON.parse(startBreakPointRes);
-
-        const endBreakPointRes = await this.cacheService.get(
-          'breakpoints:app_id:' +
-            appId +
-            ':break_point_id:' +
-            end_break_point_id,
-        );
-        const endBreakPoint = JSON.parse(endBreakPointRes);
         pathReplys = this.createCacheReplys(
           appId,
           moveFrames,
@@ -273,8 +282,6 @@ export class MoveService implements OnModuleInit {
           userId,
           start_break_point_id,
           end_break_point_id,
-          startBreakPoint.position,
-          endBreakPoint.position,
         );
 
         if (i == path.length - 2) {
@@ -298,11 +305,10 @@ export class MoveService implements OnModuleInit {
     userId,
     startBreakPointId,
     endBreakPointId,
-    startPosition,
-    endPosition,
   ) {
     const replys = [];
-
+    const startPosition = this.breakPointInfo[startBreakPointId].position;
+    const endPosition = this.breakPointInfo[endBreakPointId].position;
     const angle = this.getAngle(
       startPosition,
       {
@@ -433,6 +439,7 @@ export class MoveService implements OnModuleInit {
     user.camera.position =
       lastReply['newUserStates'][0].playerState.camera.position;
     user.camera.angle = lastReply['newUserStates'][0].playerState.camera.angle;
+    console.log('rotateForAngle-1:' + user.breakPointId);
   }
 
   getBreakPoints(actionRequest) {
@@ -498,19 +505,14 @@ export class MoveService implements OnModuleInit {
     return (angle + 360) % 360;
   }
 
-  async stop(traceId, userId, movePointIds, cameraAngle, playerAngle) {
-    const breakPointId = movePointIds.substring(movePointIds.indexOf('-') + 1);
+  async stop(traceId, userId, breakPointId, cameraAngle, playerAngle) {
+    //const breakPointId = movePointIds.substring(movePointIds.indexOf('-') + 1);
     const user = this.users[userId];
     const startBreakPointId = user.breakPointId;
     user.breakPointId = breakPointId;
     const appId = user.appId;
 
-    const breakPointRes = await this.cacheService.get(
-      'breakpoints:app_id:' + appId + ':break_point_id:' + breakPointId,
-    );
-
-    const breakPoint = JSON.parse(breakPointRes);
-
+    const breakPoint = this.breakPointInfo[breakPointId];
     user.player.position = breakPoint.position;
     user.player.angle = playerAngle;
 
@@ -551,8 +553,11 @@ export class MoveService implements OnModuleInit {
     reply.startBreakPointId = startBreakPointId;
     reply.endBreakPointId = breakPointId;
     reply['newUserStates'][0].renderInfo.isMoving = 0;
+    console.log('rotateForAngle-2:' + user.breakPointId);
     return reply;
   }
+  // 顺序旋转请求
+  seqExeJoystick = seqExeAsyncFn(this.joystick);
 
   async joystick(actionRequest) {
     try {
@@ -563,157 +568,147 @@ export class MoveService implements OnModuleInit {
       const user = this.users[userId];
       const breakPointId = user.breakPointId;
       const appId = user.appId;
-      //只是移动人物
-      if (dir_action.speed_level < 9) {
-        user.player.angle.yaw = dir_action.move_angle;
-        this.reply['newUserStates'][0]['userId'] = userId;
-        this.reply['newUserStates'][0].playerState.player.position =
-          user.player.position;
-        this.reply['newUserStates'][0].playerState.player.angle.yaw =
-          dir_action.move_angle;
 
-        this.reply['newUserStates'][0].playerState.camera.position =
-          user.camera.position;
-        this.reply['newUserStates'][0].playerState.camera.angle =
-          user.camera.angle;
+      const replys = [];
+      const step = 1;
+      const closestDis = 20; //小于这个距离就跳到邻居呼吸点
+      const distance = step * dir_action.speed_level;
+      let angle = null;
+      debugger;
+      const playerPosition = {};
+      playerPosition.x =
+        user.player.position.x + distance * Math.atan(dir_action.move_angle);
+      playerPosition.y =
+        user.player.position.y + distance * Math.tan(dir_action.move_angle);
+
+      //找到邻居点,判断user.player.position与邻居点的距离,如果距离小于closestDis,就要更新camera的position
+      let chooseBreakPointId = null;
+      const breakPoint = this.breakPointInfo[breakPointId];
+      const surroundPointIds = breakPoint.contact;
+      const neighAngles = [];
+      //找到和角度最贴近的邻居点
+      for (let i = 0; i < surroundPointIds.length; ++i) {
+        const neighPoint = this.breakPointInfo[surroundPointIds[i]];
+        const neighDistance = this.getDistance(
+          playerPosition,
+          neighPoint.position,
+        );
+        if (neighDistance < closestDis) {
+          chooseBreakPointId = surroundPointIds[i];
+        }
+        angle = this.getAngle(
+          user.player.position,
+          { x: user.player.position.x + 1, y: user.player.position.y },
+          neighPoint.position,
+        );
+        neighAngles.push(angle);
+      }
 
-        this.reply['newUserStates'][0].playerState.cameraCenter =
-          user.camera.position;
+      //方向不对的话,没有过渡内容
+      if (
+        dir_action.move_angle > Math.max(...neighAngles) ||
+        dir_action.move_angle < Math.min(...neighAngles)
+      ) {
+        return replys;
+      }
 
-        this.reply['actionResponses'][0].traceId = traceId;
+      //人物移动
+      user.player.position = JSON.parse(JSON.stringify(playerPosition));
+      user.player.angle.yaw = dir_action.move_angle;
+      angle = user.camera.angle.yaw % 45; //纠正需要
+      //通过user.camera.angle矫正相机的angle
+      const checkReplys = await this.modeifyCameraAngle(
+        angle,
+        userId,
+        traceId,
+        actionType,
+      );
+      replys.push(checkReplys);
 
+      //判断人物离该邻接点的距离是否在最小路径内,如果是,跳到这个邻接点里
+      if (chooseBreakPointId != null) {
+        //相机纠正
+        const replys = [];
+        const traceIds = [];
+        traceIds.push(traceId);
+
+        //读redis里的数据,按照frame_index的大小排序
         const key =
-          'rotateframe:app_id:' +
-          appId +
-          ':frame_index:' +
-          user.camera.angle.yaw +
-          ':break_point_id:' +
-          breakPointId;
-        const redisDataRes = await this.cacheService.get(key);
-        const redisData = JSON.parse(redisDataRes);
-        this.reply.mediaSrc =
-          '/' +
+          'moveframe:app_id:' +
           appId +
-          '/' +
+          ':start_break_point_id:' +
           breakPointId +
-          '/' +
-          redisData.directory +
-          '/' +
-          redisData.fileName +
-          '?m=' +
-          new Date().getTime();
-        console.log('人物旋转:' + user.player.angle.yaw);
-        return this.reply;
-      }
-      //选择过渡
-      else {
-        //先矫正
-        const breakPointRes = await this.cacheService.get(
-          'breakpoints:app_id:' + appId + ':break_point_id:' + breakPointId,
+          ':end_break_point_id:' +
+          chooseBreakPointId +
+          ':angle:' +
+          Math.floor(user.camera.angle.yaw / 45);
+        const moveFramesRes = await this.cacheService.get(key);
+        const moveFrames = JSON.parse(JSON.stringify(moveFramesRes));
+        const pathReplys = this.createCacheReplys(
+          appId,
+          moveFrames,
+          traceId,
+          userId,
+          breakPointId,
+          chooseBreakPointId,
         );
-        if (breakPointRes == null) {
-          return null;
-        }
-
-        const breakPoint = JSON.parse(breakPointRes);
-        const contact = breakPoint.contact;
-        let chooseBreakPointId = null;
-        let minOffsetAngle = null;
-        let neighPoint = null;
-        let angle = 0;
-        for (let i = 0; i < contact.length; ++i) {
-          neighPoint = await this.cacheService.get(
-            'breakpoints:app_id:' + appId + ':break_point_id:' + contact[i],
-          ); //通过contact[i],去redis里找
-          //通过user.player.position;neighPoint.position获得角度
-          neighPoint = JSON.parse(neighPoint);
-          angle = this.getAngle(
-            user.player.position,
-            { x: user.player.position.x + 1, y: user.player.position.y },
-            neighPoint.position,
-          );
-          if (
-            Math.abs(angle - dir_action.move_angle) < 45 &&
-            (minOffsetAngle == null ||
-              Math.abs(angle - dir_action.move_angle) < minOffsetAngle)
-          ) {
-            chooseBreakPointId = contact[i];
-            minOffsetAngle = Math.abs(angle - dir_action.move_angle);
-          }
-        }
-
-        if (chooseBreakPointId == null) {
-          return null;
-        } else {
-          //人物矫正
-          user.player.angle.yaw = angle;
-
-          //相机纠正
-          const replys = [];
-          const traceIds = [];
-          traceIds.push(traceId);
-          // debugger;
-          const checkReplys = [];
-          angle = user.camera.angle.yaw % 45; //纠正需要
-          for (let i = 0; i < angle; ++i) {
-            const reply = await this.rotateService.rotateForAngle(userId, 1);
-            reply.traceIds = [];
-            reply.traceIds.push(traceId);
-            const actionResponse = this.rotateService.createActionResponse(
-              actionType,
-              traceId,
-            );
-            reply.actionResponses = [];
-            reply.actionResponses.push(actionResponse);
-            checkReplys.push(reply);
-          }
-          replys.push(checkReplys);
-          //过渡
-          //读redis里的数据,按照frame_index的大小排序
-          const key =
-            'moveframe:app_id:' +
-            appId +
-            ':start_break_point_id:' +
-            breakPointId +
-            ':end_break_point_id:' +
-            chooseBreakPointId +
-            ':angle:' +
-            (user.camera.angle.yaw % 45);
-          const moveFramesRes = await this.cacheService.get(key);
-          if (moveFramesRes == null) {
-            return replys;
-          }
-          const moveFrames = JSON.parse(moveFramesRes);
-          //读redis里的数据
-          const startBreakPointRes = await this.cacheService.get(
-            'breakpoints:app_id:' + appId + ':break_point_id:' + breakPointId,
-          );
-          const startBreakPoint = JSON.parse(startBreakPointRes);
-
-          const endBreakPointRes = await this.cacheService.get(
-            'breakpoints:app_id:' +
-              appId +
-              ':break_point_id:' +
-              chooseBreakPointId,
-          );
-          const endBreakPoint = JSON.parse(endBreakPointRes);
-
-          const pathReplys = this.createCacheReplys(
-            appId,
-            moveFrames,
-            traceId,
-            userId,
-            breakPointId,
-            chooseBreakPointId,
-            startBreakPoint.position,
-            endBreakPoint.position,
-          );
-          replys.push(pathReplys);
-          return replys;
-        }
+        replys.push(pathReplys);
+        return replys;
+      } else {
+        return replys;
       }
     } catch (error) {
       console.log('MoveService', error);
+      debugger;
+      return null;
+    }
+  }
+
+  async modeifyCameraAngle(angle, userId, traceId, actionType) {
+    const checkReplys = [];
+    if (angle > 22) {
+      angle = 45 - angle;
+      for (let i = 0; i < angle; ++i) {
+        // console.warn('矫正一次:' + i);
+        const reply = await this.rotateService.rotateForAngle(userId, 1);
+        // console.warn(
+        //   '矫正:' + reply.newUserStates[0].playerState.camera.angle.yaw,
+        // );
+        reply.traceIds = [];
+        reply.traceIds.push(traceId);
+        const actionResponse = this.rotateService.createActionResponse(
+          actionType,
+          traceId,
+        );
+        reply.actionResponses = [];
+        reply.actionResponses.push(actionResponse);
+        checkReplys.push(reply);
+      }
+    } else if (angle != 0) {
+      for (let i = angle; i > -1; --i) {
+        // console.warn('矫正一次:' + i);
+        const reply = await this.rotateService.rotateForAngle(userId, -1);
+        // console.warn(
+        //   '矫正:' + reply.newUserStates[0].playerState.camera.angle.yaw,
+        // );
+        reply.traceIds = [];
+        reply.traceIds.push(traceId);
+        const actionResponse = this.rotateService.createActionResponse(
+          actionType,
+          traceId,
+        );
+        reply.actionResponses = [];
+        reply.actionResponses.push(actionResponse);
+        checkReplys.push(reply);
+      }
     }
+    return checkReplys;
+  }
+
+  getDistance(position1, position2) {
+    return Math.sqrt(
+      (position1.x - position2.x) * (position1.x - position2.x) +
+        (position1.y - position2.y) * (position1.y - position2.y),
+    );
   }
 }

+ 3 - 0
src/rotate/rotate.service.ts

@@ -262,6 +262,7 @@ export class RotateService {
           ':break_point_id:' +
           user.breakPointId;
         // const value = null;
+        console.log('rotateForAngle-3:' + user.breakPointId);
 
         const redisData = await this.cacheService.get(key);
         //if (redisData && redisData.length > 0) {
@@ -300,6 +301,8 @@ export class RotateService {
           value.fileName +
           '?m=' +
           new Date().getTime();
+
+        console.log('rotateForAngle-4:' + user.breakPointId);
         reply.breakPointId = user.breakPointId;
         this.replies[userId].traceIds = [];
         this.replies[userId].actionResponses = [];

+ 7 - 8
src/scene/scene.d.ts

@@ -73,16 +73,15 @@ interface RotateRequest {
   user_id: string;
   sampleRate?: number;
 }
-
 interface MoveRequest {
-  actionType: number;
-  clickingAction: {
-    clickingPoint: Point;
-    clickingType: number;
+  action_type: number;
+  clicking_action: {
+    clicking_point: Point;
+    clicking_type: number;
     extra: string;
     attitude: string;
   };
-  clickingState: {
+  clicking_state: {
     roomTypeId: string;
     person: number;
     avatarId: string;
@@ -119,8 +118,8 @@ interface MoveRequest {
     };
     cameraCenter: Point;
   };
-  traceId: string;
-  userId: string;
+  trace_id: string;
+  user_id: string;
 }
 
 interface GetBreakPointRequest {

+ 199 - 155
src/scene/scene.service.ts

@@ -3,7 +3,7 @@ import { ClientGrpc, Client } from '@nestjs/microservices';
 import { grpcClientOptions } from './grpc-scene.options';
 import { Logger } from '@nestjs/common';
 import { DataChannel } from 'node-datachannel';
-import { BehaviorSubject } from 'rxjs';
+import { BehaviorSubject, EMPTY, ignoreElements, take } from 'rxjs';
 // import * as streamBuffers from 'stream-buffers';
 import { ActionType } from './actionType';
 import { CacheService } from 'src/cache/cache.service';
@@ -11,7 +11,7 @@ import { StreamService } from './stream/stream.service';
 // import { InjectQueue } from '@nestjs/bull';
 // import { Queue } from 'bull';
 import { RotateService } from 'src/rotate/rotate.service';
-import { DelayQueue, RxQueue, ThrottleQueue, DebounceQueue } from 'rx-queue';
+import { DelayQueue, RxQueue, DebounceQueue } from 'rx-queue';
 import { MoveService } from 'src/move/move.service';
 import { GetRouterService } from 'src/get-router/get-router.service';
 import { ConfigService } from '@nestjs/config';
@@ -73,12 +73,15 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
   private requestIFrameQueueSub: any;
   private roRequestQueueSub: any;
   private rotateTimeStamp: number;
-  private lastMoveCnt = -1;
 
   private firstRender = false;
   private latestBreakPointId: number;
   private isHoldingStream = false;
   private lastMovingPointArray: MovingLastUpdateType[] = [];
+  private latestWalkingRequest: any; // 最新waking的接收值
+
+  private moveSliceLastFrame = new BehaviorSubject<MovingLastUpdateType>(null);
+  private moveSliceLastFrameSub: any;
 
   public lastMoveStreamFrame = new BehaviorSubject<StreamFrameType>({
     frame: -1,
@@ -259,7 +262,6 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
         const start = performance.now();
         // 当move时处理
         if (this.onMoving.value) {
-          this.onMoving.next(false);
           const lastStreamFrame = this.lastMoveStreamFrame.getValue();
           const metaData: StreamReplyType = JSON.parse(
             lastStreamFrame.metaData,
@@ -273,6 +275,7 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
           const cameraAngle = newUserStates.playerState.camera.angle;
           const playerAngle = newUserStates.playerState.player.angle;
           console.log('stop-data', trace_id, userId, cameraAngle, cameraAngle);
+          //debugger;
           redisMeta = await this.moveService.stop(
             trace_id,
             userId,
@@ -281,6 +284,8 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
             playerAngle,
           );
           console.log('stop-redisMeta', redisMeta);
+          this.onMoving.next(false);
+          this.cleanMoveSteam();
           // redisMeta = await this.rotateService.rotate(request);
         } else {
           // 正常rotate
@@ -335,95 +340,144 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
     // );
   }
 
-  async walking(req) {
-    try {
-      // if (this.clickQueueSub) {
-      //   this.clickQueueSub.unsubscribe();
-      //   this.clickQueueSub = null;
-      // }
-      // this.clickQueue.next(req);
-      // console.log('walking', this.clickQueueSub, JSON.stringify(req));
-      // if (!this.clickQueueSub) {
-      // this.clickQueueSub = this.clickQueue.subscribe(async (request) => {
+  async walking(request: MoveRequest) {
+    this.latestWalkingRequest = request;
+    console.log('walking', request);
+    // 进入正常walking流程
+    if (!this.onMoving.getValue()) {
+      this.latestWalkingRequest = null;
+      this.handleWalking(request);
+    }
+    // 监听每小段最后一zhen
+    if (!this.moveSliceLastFrameSub) {
+      this.moveSliceLastFrameSub = this.moveSliceLastFrame.subscribe(
+        async (frame: MovingLastUpdateType) => {
+          //TODO 正在行走时,有新的reqest
+          if (this.latestWalkingRequest && this.onMoving.value) {
+            console.log('中断的小段', frame);
+            // this.moveQueue.complete();
+            // this.moveQueue.of('');
+            // TODO 中断move队列 ?优化如何清空
+            // this.moveQueue.pipe(ignoreElements());
+            this.moveQueueSubscription.unsubscribe();
+            this.moveQueueSubscription = null;
+            //step1 执行stop方法
+            const metaData: StreamReplyType = frame.metaData;
+            const newUserStates: NewUserStatesType =
+              metaData.newUserStates.find(
+                (item) => item.userId === this.user_id,
+              );
+            const trace_id = metaData.traceIds[0];
+            const userId = newUserStates.userId;
+            const breakPointId = metaData.endBreakPointId;
+            const cameraAngle = newUserStates.playerState.camera.angle;
+            const playerAngle = newUserStates.playerState.player.angle;
+            console.log(
+              'stop-data',
+              trace_id,
+              userId,
+              cameraAngle,
+              cameraAngle,
+            );
+            const redisMeta = await this.moveService.stop(
+              trace_id,
+              userId,
+              breakPointId,
+              cameraAngle,
+              playerAngle,
+            );
+            console.log('stop-redisMeta', redisMeta);
+            // 2. 中断重新walking
+            this.handleReWalking(this.latestWalkingRequest);
+          }
+        },
+      );
+    }
+  }
 
-      if (!this.onMoving.getValue()) {
-        const start = performance.now();
-        const user = this.moveService.users[this.user_id];
-        console.log('进入1 - searchRoad');
-        console.log('path-start' + user.breakPointId);
-        const path = await this.getRouterService.searchRoad(
-          user.appId,
-          user.breakPointId,
-          req.clicking_action.clicking_point,
-        );
-        console.log('walking-path', path);
-        if (!path) {
-          console.log('不存在--path', path);
-          this.resumeStream();
-          return;
+  /**
+   * 行走队列处理器
+   * @param request MoveRequest
+   * @returns void
+   */
+
+  async handleWalking(request: MoveRequest): Promise<void> {
+    try {
+      // if (!this.onMoving.getValue()) {
+      const start = performance.now();
+      const user = this.moveService.users[this.user_id];
+      console.log('进入1 - searchRoad');
+      console.log('path-start' + user.breakPointId);
+      const path = await this.getRouterService.searchRoad(
+        user.appId,
+        user.breakPointId,
+        request.clicking_action.clicking_point,
+      );
+      console.log('walking-path', path);
+      if (!path) {
+        console.log('不存在--path', path);
+        this.resumeStream();
+        return;
+      }
+      // debugger;
+      const walkingRes = await this.moveService.move(path, request);
+
+      // console.log('walking', walkingRes);
+      // debugger;
+      if (walkingRes && !this.onMoving.value) {
+        // console.log('walkingRes-front', walkingRes);
+        // shift出前第一个镜头数据
+        const rotateCamData = walkingRes[0];
+        console.log('rotateCamData', rotateCamData.length);
+        if (rotateCamData?.length) {
+          // 头数组[0] rotate 序列, 头是关键key
+          walkingRes[0].forEach((item: StreamReplyType, index: number) => {
+            item.mType = 'rotate';
+            item.DIR = index === 0 ? 1 : 3;
+          });
+        } else {
+          console.log('rotateCamData无数据');
         }
-        // debugger;
-        const walkingRes = await this.moveService.move(path, req);
-
-        // console.log('walking', walkingRes);
-        // debugger;
-        if (walkingRes && !this.onMoving.value) {
-          // console.log('walkingRes-front', walkingRes);
-          // shift出前第一个镜头数据
-          const rotateCamData = walkingRes[0];
-          console.log('rotateCamData', rotateCamData.length);
-          if (rotateCamData?.length) {
-            // 头数组[0] rotate 序列, 头是关键key
-            walkingRes[0].forEach((item: StreamReplyType, index: number) => {
-              item.mType = 'rotate';
-              item.DIR = index === 0 ? 1 : 3;
-            });
-          } else {
-            console.log('rotateCamData无数据');
-          }
 
-          // 二维数组 做move 序列, move类型
-          if (walkingRes?.length >= 1) {
-            for (let i = 1; i < walkingRes.length; i++) {
-              console.log('walkingRes', walkingRes[i]);
-              Array.from(walkingRes[i]).forEach(
-                (item: StreamReplyType, index: number) => {
-                  const dir = this.isHeaderOrLast(
-                    index,
-                    walkingRes[i].length - 1,
-                  );
-                  item.DIR = dir ? 1 : 3;
-                  //将每段最后一个推入lastMovingPointArray
-                  if (index === walkingRes[i].length - 1) {
-                    this.lastMovingPointArray.push({
-                      mediaSrc: item.mediaSrc,
-                      metaData: item,
-                    });
-                  }
-                },
-              );
-            }
+        // 二维数组 做move 序列, move类型
+        if (walkingRes && walkingRes?.length >= 1) {
+          for (let i = 1; i < walkingRes.length; i++) {
+            Array.from(walkingRes[i]).forEach(
+              (item: StreamReplyType, index: number) => {
+                const dir = this.isHeaderOrLast(
+                  index,
+                  walkingRes[i].length - 1,
+                );
+                item.DIR = dir ? 1 : 3;
+                //将每段最后一个推入lastMovingPointArray
+                if (index === walkingRes[i].length - 1) {
+                  this.lastMovingPointArray.push({
+                    mediaSrc: item.mediaSrc,
+                    metaData: item,
+                  });
+                }
+              },
+            );
           }
+        }
 
-          // walkingRes marker to everybody
-          const seqs = Array.from(
-            walkingRes,
-          ).flat() as any as StreamReplyType[];
-
-          if (seqs?.length) {
-            console.log('walking --总序列--seqs-2', seqs.length);
-            const stop = performance.now();
-            const inMillSeconds = stop - start;
-            const rounded = Number(inMillSeconds).toFixed(3);
-            console.log(`[timer]-move-入队列前:-->${rounded}ms`);
-
-            this.handleSeqMoving(seqs);
-          } else {
-            console.error('walking-move无数据');
-            this.cleanMoveSteam();
-            this.resumeStream();
-          }
+        // walkingRes marker to everybody
+        const seqs = Array.from(walkingRes).flat() as any as StreamReplyType[];
+
+        if (seqs?.length) {
+          console.log('walking --总序列--seqs-2', seqs.length);
+          const stop = performance.now();
+          const inMillSeconds = stop - start;
+          const rounded = Number(inMillSeconds).toFixed(3);
+          console.log(`[timer]-move-入队列前:-->${rounded}ms`);
+
+          this.handleSeqMoving(seqs);
+        } else {
+          console.error('walking-move无数据');
+          this.cleanMoveSteam();
+          this.resumeStream();
         }
+        // }
       }
       // });
       // }
@@ -434,67 +488,67 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
     }
   }
 
+  /**
+   *  改变路线后的walking队列处理(中转)
+   * @param request MoveRequest
+   */
+  handleReWalking(request: MoveRequest) {
+    this.latestWalkingRequest = null;
+    this.handleWalking(request);
+  }
+
+  /***
+   * joystick
+   */
+
   async joystick(request: JoystickRequest) {
     try {
-      this.joystickQueue.next(request);
-      if (!this.joystickSub) {
-        this.joystickSub = this.joystickQueue.subscribe(
-          async (joystickRequest) => {
-            const joystickRes = await this.moveService.joystick(
-              joystickRequest,
-            );
-
-            // 有数据 [0]是rotate数据,[1-infinity]是walking数据
-            if (Array.isArray(joystickRes)) {
-              // shift出前第一个镜头数据
-
-              const rotateCamData = joystickRes.shift();
-              console.log('rotateCamData', rotateCamData.length);
-              if (rotateCamData?.length) {
-                // 头数组[0] rotate 序列, 头是关键key
-                joystickRes[0].forEach(
-                  (item: StreamReplyType, index: number) => {
-                    item.mType = 'rotate';
-                    item.DIR = index === 0 ? 1 : 3;
-                  },
+      //const joystickRes = await this.moveService.joystick(request);
+      const joystickRes = await this.moveService.seqExeJoystick(request);
+      // 有数据 [0]是rotate数据,[1-infinity]是walking数据
+      if (Array.isArray(joystickRes)) {
+        // shift出前第一个镜头数据
+
+        const rotateCamData = joystickRes.shift();
+        console.log('rotateCamData', rotateCamData.length);
+        if (rotateCamData?.length) {
+          // 头数组[0] rotate 序列, 头是关键key
+          joystickRes[0].forEach((item: StreamReplyType, index: number) => {
+            item.mType = 'rotate';
+            item.DIR = index === 0 ? 1 : 3;
+          });
+        } else {
+          console.log('rotateCamData无数据');
+        }
+        // 二维数组 做move 序列, move类型
+        if (joystickRes?.length >= 1) {
+          for (let i = 1; i < joystickRes.length; i++) {
+            console.log('joystickRes', joystickRes[i]);
+            Array.from(joystickRes[i]).forEach(
+              (item: StreamReplyType, index: number) => {
+                const dir = this.isHeaderOrLast(
+                  index,
+                  joystickRes[i].length - 1,
                 );
-              } else {
-                console.log('rotateCamData无数据');
-              }
-              // 二维数组 做move 序列, move类型
-              if (joystickRes?.length >= 1) {
-                for (let i = 1; i < joystickRes.length; i++) {
-                  console.log('joystickRes', joystickRes[i]);
-                  Array.from(joystickRes[i]).forEach(
-                    (item: StreamReplyType, index: number) => {
-                      const dir = this.isHeaderOrLast(
-                        index,
-                        joystickRes[i].length - 1,
-                      );
-                      item.DIR = dir ? 1 : 3;
-                    },
-                  );
-                }
-              }
-
-              const seqs = Array.from(
-                joystickRes,
-              ).flat() as any as StreamReplyType[];
+                item.DIR = dir ? 1 : 3;
+              },
+            );
+          }
+        }
+        const seqs = Array.from(joystickRes).flat() as any as StreamReplyType[];
 
-              if (seqs?.length) {
-                console.log('joystickRes-seqs', seqs.length);
-                this.handleSeqMoving(seqs);
-              } else {
-                console.warn('joystick-move无数据');
-              }
-            } else {
-              console.log('转交数据');
-              this.streamService.pushNormalDataToStream(request);
-            }
-          },
-        );
+        if (seqs?.length) {
+          console.log('joystickRes-seqs', seqs.length);
+          this.handleSeqMoving(seqs);
+        } else {
+          console.warn('joystick-move无数据');
+        }
+      } else {
+        console.log('转交数据');
+        // this.streamService.pushNormalDataToStream(request);
       }
     } catch (error) {
+      console.error('joystick错误', error);
       this.logger.error('joystick', error);
     }
   }
@@ -532,7 +586,6 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
   cleanMoveSteam() {
     if (this.moveQueueSubscription) {
       this.moveQueueSubscription.unsubscribe();
-      this.lastMoveCnt = -1;
       this.moveQueueSubscription = null;
     }
     if (this.walkingSub) {
@@ -591,23 +644,14 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
           // console.log('path-update', breakPointId);
           this.moveService.updateUser(userId, breakPointId, lastReply);
           this.lastMovingPointArray.splice(isLastFrameIndex, 1);
+          //TODO 队列每一段最后one frame
+          this.moveSliceLastFrame.next(currentMeta);
         }
 
         if (res.done) {
           clearTimeout(this._moveTimeout);
           this._moveTimeout = setTimeout(() => {
             console.log('move 交权给空流,当前pts', res.frame);
-            //TODO 每个结束点 updateUser metaData
-            // const lastFrame = this.lastMoveStreamFrame.getValue();
-            // const lastFrameMeta: StreamReplyType = JSON.parse(
-            //   lastFrame.metaData,
-            // );
-
-            // const userId = this.user_id;
-            // const breakPointId = lastFrameMeta.endBreakPointId;
-            // const lastReply = lastFrameMeta;
-            // console.log('path-update', breakPointId);
-            // this.moveService.updateUser(userId, breakPointId, lastReply);
             this.frameCnt.next(res.frame);
             this.resumeStream();
             this.rotateframeCnt = -1;
@@ -655,7 +699,7 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
           const msg: RTCMessageRequest = JSON.parse(message);
           switch (msg.action_type) {
             case ActionType.walk:
-              const walk = msg;
+              const walk = msg as any as MoveRequest;
               this.walking(walk);
               break;
             case ActionType.joystick: