move.service.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. import {
  2. ConsoleLogger,
  3. Injectable,
  4. Logger,
  5. OnModuleInit,
  6. } from '@nestjs/common';
  7. import { readFileSync } from 'fs';
  8. import { join } from 'path';
  9. import { CacheService } from 'src/cache/cache.service';
  10. import { RotateService } from 'src/rotate/rotate.service';
  11. // import * as BreakPointIds from '../../ws/points-BreakPointId.json';
  12. // import { SceneService } from 'src/scene/scene.service';
  13. @Injectable()
  14. export class MoveService implements OnModuleInit {
  15. constructor(
  16. private cacheService: CacheService,
  17. private rotateService: RotateService,
  18. ) {}
  19. private logger: Logger = new Logger('MoveService');
  20. private Actions = {
  21. Clicking: 1,
  22. Rotation: 1014,
  23. Joystick: 15,
  24. };
  25. public users = this.rotateService.users;
  26. private reply = {
  27. traceIds: [],
  28. vehicle: null,
  29. mediaSrc: null,
  30. newUserStates: [
  31. {
  32. userId: 'dcff36ae4fc1d',
  33. playerState: {
  34. roomTypeId: '',
  35. person: 0,
  36. avatarId: '',
  37. skinId: '',
  38. roomId: '',
  39. isHost: false,
  40. isFollowHost: false,
  41. skinDataVersion: '',
  42. avatarComponents: '',
  43. nickName: '',
  44. movingMode: 0,
  45. attitude: '',
  46. areaName: '',
  47. pathName: '',
  48. pathId: '',
  49. avatarSize: 1,
  50. extra: '',
  51. prioritySync: false,
  52. player: {
  53. position: { x: -700, y: 0, z: 0 },
  54. angle: {
  55. pitch: 0,
  56. yaw: 0,
  57. roll: 0,
  58. },
  59. },
  60. camera: {
  61. position: { x: -1145, y: 0, z: 160 },
  62. angle: {
  63. pitch: 0,
  64. yaw: 0,
  65. roll: 0,
  66. },
  67. },
  68. cameraCenter: { x: -700, y: 0, z: 0 },
  69. },
  70. renderInfo: {
  71. renderType: 0,
  72. videoFrame: null,
  73. cameraStateType: 3,
  74. isMoving: 1,
  75. needIfr: 0,
  76. isVideo: 0,
  77. stillFrame: 0,
  78. isRotating: 0,
  79. isFollowing: 0,
  80. clientPanoTitlesBitmap: [],
  81. clientPanoTreceId: '',
  82. prefetchVideoId: '',
  83. noMedia: false,
  84. },
  85. event: null,
  86. relation: 1,
  87. },
  88. ],
  89. actionResponses: [
  90. {
  91. actionType: 1,
  92. pointType: 100,
  93. extra: '',
  94. traceId: '',
  95. packetId: '',
  96. nps: [],
  97. peopleNum: 0,
  98. zoneId: '',
  99. echoMsg: '',
  100. reserveDetail: null,
  101. userWithAvatarList: [],
  102. newUserStates: [],
  103. code: 0,
  104. msg: '',
  105. },
  106. ],
  107. getStateType: 0,
  108. code: 0,
  109. msg: 'OK',
  110. };
  111. private breakPointInfo: any;
  112. async onModuleInit() {
  113. try {
  114. const path = join(__dirname, '../ws/points-BreakPointId.json');
  115. // const path = join(__dirname, '../ws/demo1.json');
  116. const data = await readFileSync(path);
  117. const BreakPointInfo = JSON.parse(Buffer.from(data).toString('utf-8'));
  118. this.breakPointInfo = BreakPointInfo;
  119. // console.log('BreakPointInfo', BreakPointInfo);
  120. } catch (error) {
  121. this.logger.error('load-json-error', error);
  122. }
  123. }
  124. init(app_id, userId) {
  125. const user = {
  126. appId: null,
  127. userId: null,
  128. breakPointId: null,
  129. roomId: null,
  130. player: {
  131. position: { x: -700, y: 0, z: 0 },
  132. angle: {
  133. pitch: 0,
  134. yaw: 0,
  135. roll: 0,
  136. },
  137. },
  138. camera: {
  139. position: { x: -1145, y: 0, z: 160 },
  140. angle: {
  141. pitch: 0,
  142. yaw: 0,
  143. roll: 0,
  144. },
  145. },
  146. rotateInfo: {
  147. frameIndex: 0,
  148. horizontal_move: 0,
  149. },
  150. moveInfo: {},
  151. // traceIds: [],
  152. // actionResponses:[]
  153. };
  154. user.appId = app_id;
  155. user.userId = userId;
  156. user.breakPointId = 100;
  157. this.users[userId] = user;
  158. }
  159. async move(pathArray, actionRequest) {
  160. try {
  161. const userId = actionRequest['user_id'];
  162. const traceId = actionRequest['trace_id'];
  163. const actionType = actionRequest['action_type'];
  164. const user = this.users[userId];
  165. const appId = user.appId;
  166. const path = pathArray || [100, 101, 102]; //需要计算路径
  167. const angle = user.camera.angle.yaw % 45; //纠正需要
  168. const replys = [];
  169. const traceIds = [];
  170. traceIds.push(traceId);
  171. // debugger;
  172. //纠正,旋转传到缓存里
  173. const checkReplys = [];
  174. // console.log('矫正: ' + angle + ' 度');
  175. if (angle > 22) {
  176. for (let i = 0; i < angle; ++i) {
  177. // console.warn('矫正一次:' + i);
  178. const reply = await this.rotateService.rotateForAngle(userId, 1);
  179. // console.warn(
  180. // '矫正:' + reply.newUserStates[0].playerState.camera.angle.yaw,
  181. // );
  182. reply.traceIds = [];
  183. reply.traceIds.push(traceId);
  184. const actionResponse = this.rotateService.createActionResponse(
  185. actionType,
  186. traceId,
  187. );
  188. reply.actionResponses = [];
  189. reply.actionResponses.push(actionResponse);
  190. checkReplys.push(reply);
  191. }
  192. } else if(angle != 0){
  193. for (let i = angle; i > -1; --i) {
  194. // console.warn('矫正一次:' + i);
  195. const reply = await this.rotateService.rotateForAngle(userId, -1);
  196. // console.warn(
  197. // '矫正:' + reply.newUserStates[0].playerState.camera.angle.yaw,
  198. // );
  199. reply.traceIds = [];
  200. reply.traceIds.push(traceId);
  201. const actionResponse = this.rotateService.createActionResponse(
  202. actionType,
  203. traceId,
  204. );
  205. reply.actionResponses = [];
  206. reply.actionResponses.push(actionResponse);
  207. checkReplys.push(reply);
  208. }
  209. }
  210. //replys['P' + user.breakPointId + 'T' + user.breakPointId] = checkReplys;
  211. replys.push(checkReplys);
  212. //过渡传到缓存里
  213. this.reply.traceIds = traceIds;
  214. this.reply['newUserStates'][0].userId = userId;
  215. this.reply['actionResponses'][0].traceId = traceId;
  216. const index = Math.floor(user.camera.angle.yaw / 45); //过渡需要
  217. for (let i = 0; i < path.length - 1; ++i) {
  218. let pathReplys = [];
  219. const start_break_point_id = path[i];
  220. const end_break_point_id = path[i + 1];
  221. //读redis里的数据,按照frame_index的大小排序
  222. const key =
  223. 'moveframe:app_id:' +
  224. appId +
  225. ':start_break_point_id:' +
  226. start_break_point_id +
  227. ':end_break_point_id:' +
  228. end_break_point_id +
  229. ':angle:' +
  230. index;
  231. const moveFramesRes = await this.cacheService.get(key);
  232. if (moveFramesRes == null) {
  233. return replys;
  234. }
  235. const moveFrames = JSON.parse(moveFramesRes);
  236. // debugger;
  237. //读redis里的数据
  238. const startBreakPointRes = await this.cacheService.get(
  239. 'breakpoints:app_id:' +
  240. appId +
  241. ':break_point_id:' +
  242. start_break_point_id,
  243. );
  244. const startBreakPoint = JSON.parse(startBreakPointRes);
  245. const endBreakPointRes = await this.cacheService.get(
  246. 'breakpoints:app_id:' +
  247. appId +
  248. ':break_point_id:' +
  249. end_break_point_id,
  250. );
  251. const endBreakPoint = JSON.parse(endBreakPointRes);
  252. pathReplys = this.createCacheReplys(
  253. appId,
  254. moveFrames,
  255. traceId,
  256. userId,
  257. start_break_point_id,
  258. startBreakPoint.position,
  259. endBreakPoint.position,
  260. );
  261. if (i == path.length - 2) {
  262. pathReplys[pathReplys.length - 1][
  263. 'newUserStates'
  264. ][0].renderInfo.isMoving = 0;
  265. }
  266. replys.push(pathReplys);
  267. //replys['P' + start_break_point_id + 'T' + end_break_point_id] =pathReplys;
  268. }
  269. return replys;
  270. } catch (error) {
  271. console.log('MoveService', error);
  272. }
  273. }
  274. createCacheReplys(
  275. appId,
  276. moveFrames,
  277. traceId,
  278. userId,
  279. breakPointId,
  280. startPosition,
  281. endPosition,
  282. ) {
  283. const replys = [];
  284. const angle = this.getAngle(
  285. startPosition,
  286. {
  287. x: startPosition.x + 1,
  288. y: startPosition.y,
  289. },
  290. endPosition,
  291. );
  292. for (let i = 1; i < moveFrames.length; i += 2) {
  293. const moveFrame = moveFrames[i];
  294. const reply = JSON.parse(JSON.stringify(this.reply));
  295. reply.traceIds.push(traceId);
  296. reply['newUserStates'][0].userId = userId;
  297. reply['newUserStates'][0].playerState.player.position = {
  298. x:
  299. startPosition.x +
  300. ((endPosition.x - startPosition.x) / moveFrames.length) * i,
  301. y:
  302. startPosition.y +
  303. ((endPosition.y - startPosition.y) / moveFrames.length) * i,
  304. z:
  305. startPosition.z +
  306. ((endPosition.z - startPosition.z) / moveFrames.length) * i,
  307. };
  308. reply['newUserStates'][0].playerState.player.angle.yaw = angle;
  309. reply['newUserStates'][0].playerState.camera.position =
  310. moveFrame.camera_position;
  311. if (moveFrame.camera_angle.yaw < 0) {
  312. moveFrame.camera_angle.yaw += 360;
  313. } else if (moveFrame.camera_angle.yaw > 359) {
  314. moveFrame.camera_angle.yaw -= 360;
  315. }
  316. reply['newUserStates'][0].playerState.camera.angle =
  317. moveFrame.camera_angle;
  318. reply['newUserStates'][0].playerState.cameraCenter =
  319. reply['newUserStates'][0].playerState.player.position;
  320. reply['actionResponses'][0].traceId = traceId;
  321. reply.mediaSrc =
  322. '/' +
  323. appId +
  324. '/' +
  325. breakPointId +
  326. '/' +
  327. moveFrame.file_name.substring(0, moveFrame.file_name.indexOf('.')) +
  328. '/' +
  329. moveFrame.file_name +
  330. '?m=' +
  331. new Date().getTime();
  332. reply.breakPointId = breakPointId;
  333. replys.push(reply);
  334. }
  335. return replys;
  336. }
  337. //需要通知user,人物和相机走到哪一个呼吸点位了
  338. updateUser(userId, breakPointId, lastReply) {
  339. const user = this.users[userId];
  340. user.breakPointId = breakPointId;
  341. // debugger;
  342. user.player.position =
  343. lastReply['newUserStates'][0].playerState.player.position;
  344. user.player.angle = lastReply['newUserStates'][0].playerState.player.angle;
  345. user.camera.position =
  346. lastReply['newUserStates'][0].playerState.camera.position;
  347. user.camera.angle = lastReply['newUserStates'][0].playerState.camera.angle;
  348. }
  349. getBreakPoints(actionRequest) {
  350. const userId = actionRequest['user_id'];
  351. const traceId = actionRequest['trace_id'];
  352. const actionType = actionRequest['action_type'];
  353. const user = this.users[userId];
  354. const appId = user.appId;
  355. const breakPointId = user.breakPointId;
  356. const reply = {
  357. actionType: actionType,
  358. pointType: 100,
  359. extra: '',
  360. traceId: traceId,
  361. packetId: '',
  362. nps: [],
  363. peopleNum: 0,
  364. zoneId: '',
  365. echoMsg: '',
  366. reserveDetail: null,
  367. userWithAvatarList: [],
  368. newUserStates: [],
  369. code: 0,
  370. msg: '',
  371. };
  372. //const breakPoints = await this.cacheService.get('breakpoints:app_id:'+appId+':break_point_id:'+breakPointId);
  373. //获取redis表全部元素,'breakpoints:app_id:'+appId+':break_point_id:'开头的
  374. //const keys = await this.cacheService.keys(`breakpoints:app_id:${appId}*`);
  375. for (const key in this.breakPointInfo) {
  376. const breakPoint = this.breakPointInfo[key];
  377. //const breakPoint = JSON.parse(breakPointRes);
  378. //const position = breakPoint.position;
  379. reply['nps'].push({
  380. position: breakPoint.position,
  381. breakPointId: Number(key),
  382. });
  383. }
  384. // for (let i = 0; i < keys.length; ++i) {
  385. // const breakPointRes = await this.cacheService.get(keys[i]);
  386. // const breakPoint = JSON.parse(breakPointRes);
  387. // const position = breakPoint.position;
  388. // reply['nps'].push({
  389. // position: position,
  390. // breakPointId: breakPoint.breakPointId,
  391. // });
  392. // }
  393. return reply;
  394. }
  395. getAngle(point, point1, point2) {
  396. const x1 = point1.x - point.x;
  397. const y1 = point1.y - point.y;
  398. const x2 = point2.x - point.x;
  399. const y2 = point2.y - point.y;
  400. const dot = x1 * x2 + y1 * y2;
  401. const det = x1 * y2 - y1 * x2;
  402. const angle = (Math.atan2(det, dot) / Math.PI) * 180;
  403. return (angle + 360) % 360;
  404. }
  405. async stop(traceId, userId, movePointIds, cameraAngle, playerAngle) {
  406. const breakPointId = movePointIds.substring(movePointIds.indexOf('-') + 1);
  407. const user = this.users[userId];
  408. user.breakPointId = breakPointId;
  409. const appId = user.appId;
  410. const breakPointRes = await this.cacheService.get(
  411. 'breakpoints:app_id:' + appId + ':break_point_id:' + breakPointId,
  412. );
  413. const breakPoint = JSON.parse(breakPointRes);
  414. user.player.position = breakPoint.position;
  415. user.player.angle = playerAngle;
  416. const rotateKey =
  417. 'rotateframe:app_id:' +
  418. appId +
  419. ':frame_index:' +
  420. cameraAngle.yaw +
  421. ':break_point_id:' +
  422. breakPointId;
  423. const rotateDataRes = await this.cacheService.get(rotateKey);
  424. const rotateData = JSON.parse(rotateDataRes);
  425. user.camera.position = rotateData.cameraPosition;
  426. user.camera.angle = rotateData.cameraAngle;
  427. const reply = JSON.parse(JSON.stringify(this.reply));
  428. reply.traceIds.push(traceId);
  429. reply['newUserStates'][0].userId = userId;
  430. reply['newUserStates'][0].playerState.player.position = breakPoint.position;
  431. reply['newUserStates'][0].playerState.player.angle = playerAngle;
  432. reply['newUserStates'][0].playerState.camera.position =
  433. rotateData.cameraPosition;
  434. reply['newUserStates'][0].playerState.camera.angle = rotateData.cameraAngle;
  435. reply['newUserStates'][0].playerState.cameraCenter = breakPoint.position;
  436. reply['actionResponses'][0].traceId = traceId;
  437. reply.mediaSrc =
  438. '/' +
  439. appId +
  440. '/' +
  441. breakPointId +
  442. '/' +
  443. rotateData.directory +
  444. '/' +
  445. rotateData.fileName +
  446. '?m=' +
  447. new Date().getTime();
  448. reply.breakPointId = breakPointId;
  449. reply['newUserStates'][0].renderInfo.isMoving = 0;
  450. return reply;
  451. }
  452. async joystick(actionRequest) {
  453. try {
  454. const userId = actionRequest['user_id'];
  455. const traceId = actionRequest['trace_id'];
  456. const dir_action = actionRequest['dir_action'];
  457. const actionType = actionRequest['action_type'];
  458. const user = this.users[userId];
  459. const breakPointId = user.breakPointId;
  460. const appId = user.appId;
  461. //只是移动人物
  462. if (dir_action.speed_level < 9) {
  463. user.player.angle.yaw = dir_action.move_angle;
  464. this.reply['newUserStates'][0]['userId'] = userId;
  465. this.reply['newUserStates'][0].playerState.player.position =
  466. user.player.position;
  467. this.reply['newUserStates'][0].playerState.player.angle.yaw =
  468. dir_action.move_angle;
  469. this.reply['newUserStates'][0].playerState.camera.position =
  470. user.camera.position;
  471. this.reply['newUserStates'][0].playerState.camera.angle =
  472. user.camera.angle;
  473. this.reply['newUserStates'][0].playerState.cameraCenter =
  474. user.camera.position;
  475. this.reply['actionResponses'][0].traceId = traceId;
  476. const key =
  477. 'rotateframe:app_id:' +
  478. appId +
  479. ':frame_index:' +
  480. user.camera.angle.yaw +
  481. ':break_point_id:' +
  482. breakPointId;
  483. const redisDataRes = await this.cacheService.get(key);
  484. const redisData = JSON.parse(redisDataRes);
  485. this.reply.mediaSrc =
  486. '/' +
  487. appId +
  488. '/' +
  489. breakPointId +
  490. '/' +
  491. redisData.directory +
  492. '/' +
  493. redisData.fileName +
  494. '?m=' +
  495. new Date().getTime();
  496. console.log('人物旋转:' + user.player.angle.yaw);
  497. return this.reply;
  498. }
  499. //选择过渡
  500. else {
  501. //先矫正
  502. const breakPointRes = await this.cacheService.get(
  503. 'breakpoints:app_id:' + appId + ':break_point_id:' + breakPointId,
  504. );
  505. if (breakPointRes == null) {
  506. return null;
  507. }
  508. const breakPoint = JSON.parse(breakPointRes);
  509. const contact = breakPoint.contact;
  510. let chooseBreakPointId = null;
  511. let minOffsetAngle = null;
  512. let neighPoint = null;
  513. let angle = 0;
  514. for (let i = 0; i < contact.length; ++i) {
  515. neighPoint = await this.cacheService.get(
  516. 'breakpoints:app_id:' + appId + ':break_point_id:' + contact[i],
  517. ); //通过contact[i],去redis里找
  518. //通过user.player.position;neighPoint.position获得角度
  519. neighPoint = JSON.parse(neighPoint);
  520. angle = this.getAngle(
  521. user.player.position,
  522. { x: user.player.position.x + 1, y: user.player.position.y },
  523. neighPoint.position,
  524. );
  525. if (
  526. Math.abs(angle - dir_action.move_angle) < 45 &&
  527. (minOffsetAngle == null ||
  528. Math.abs(angle - dir_action.move_angle) < minOffsetAngle)
  529. ) {
  530. chooseBreakPointId = contact[i];
  531. minOffsetAngle = Math.abs(angle - dir_action.move_angle);
  532. }
  533. }
  534. if (chooseBreakPointId == null) {
  535. return null;
  536. } else {
  537. //人物矫正
  538. user.player.angle.yaw = angle;
  539. //相机纠正
  540. const replys = [];
  541. const traceIds = [];
  542. traceIds.push(traceId);
  543. // debugger;
  544. const checkReplys = [];
  545. angle = user.camera.angle.yaw % 45; //纠正需要
  546. for (let i = 0; i < angle; ++i) {
  547. const reply = await this.rotateService.rotateForAngle(userId, 1);
  548. reply.traceIds = [];
  549. reply.traceIds.push(traceId);
  550. const actionResponse = this.rotateService.createActionResponse(
  551. actionType,
  552. traceId,
  553. );
  554. reply.actionResponses = [];
  555. reply.actionResponses.push(actionResponse);
  556. checkReplys.push(reply);
  557. }
  558. replys.push(checkReplys);
  559. //过渡
  560. //读redis里的数据,按照frame_index的大小排序
  561. const key =
  562. 'moveframe:app_id:' +
  563. appId +
  564. ':start_break_point_id:' +
  565. breakPointId +
  566. ':end_break_point_id:' +
  567. chooseBreakPointId +
  568. ':angle:' +
  569. (user.camera.angle.yaw % 45);
  570. const moveFramesRes = await this.cacheService.get(key);
  571. if (moveFramesRes == null) {
  572. return replys;
  573. }
  574. const moveFrames = JSON.parse(moveFramesRes);
  575. //读redis里的数据
  576. const startBreakPointRes = await this.cacheService.get(
  577. 'breakpoints:app_id:' + appId + ':break_point_id:' + breakPointId,
  578. );
  579. const startBreakPoint = JSON.parse(startBreakPointRes);
  580. const endBreakPointRes = await this.cacheService.get(
  581. 'breakpoints:app_id:' +
  582. appId +
  583. ':break_point_id:' +
  584. chooseBreakPointId,
  585. );
  586. const endBreakPoint = JSON.parse(endBreakPointRes);
  587. const pathReplys = this.createCacheReplys(
  588. appId,
  589. moveFrames,
  590. traceId,
  591. userId,
  592. breakPointId,
  593. startBreakPoint.position,
  594. endBreakPoint.position,
  595. );
  596. replys.push(pathReplys);
  597. return replys;
  598. }
  599. }
  600. } catch (error) {
  601. console.log('MoveService', error);
  602. }
  603. }
  604. }