rotate.service.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. import { Injectable, Logger } from '@nestjs/common';
  2. import { ConfigService } from '@nestjs/config';
  3. import { CacheService } from 'src/cache/cache.service';
  4. // import { SceneService } from 'src/scene/scene.service';
  5. const seqExeAsyncFn = (asyncFn) => {
  6. let runPromise = null;
  7. return function seq(...args) {
  8. if (!runPromise) {
  9. //debugger;
  10. runPromise = asyncFn.apply(this, args);
  11. runPromise.then((data) => {
  12. //debugger;
  13. // console.log('seq result', data);
  14. });
  15. runPromise.then(() => (runPromise = null));
  16. return runPromise;
  17. } else {
  18. return runPromise.then(() => seq.apply(this, args));
  19. }
  20. };
  21. };
  22. @Injectable()
  23. export class RotateService {
  24. constructor(
  25. private cacheService: CacheService, // private sceneService: SceneService,
  26. private configService: ConfigService,
  27. ) {}
  28. private actionRequestPool = {};
  29. private logger: Logger = new Logger('rotateService');
  30. private Actions = {
  31. Clicking: 1,
  32. Rotation: 1014,
  33. Joystick: 15,
  34. };
  35. public users = {};
  36. private replies = {};
  37. init(app_id: string, userId: string) {
  38. const user = {
  39. appId: null,
  40. userId: null,
  41. breakPointId: null,
  42. roomId: null,
  43. player: {
  44. position: { x: -800.0, y: 100.0, z: 0.0 },
  45. angle: {
  46. pitch: 0,
  47. yaw: 0,
  48. roll: 0,
  49. },
  50. },
  51. camera: {
  52. position: { x: -1141.6719970703125, y: 94.03607940673828, z: 120.0 },
  53. angle: {
  54. pitch: 0,
  55. yaw: 0,
  56. roll: 0,
  57. },
  58. },
  59. rotateInfo: {
  60. frameIndex: 0,
  61. horizontal_move: 0,
  62. },
  63. moveInfo: {},
  64. // traceIds: [],
  65. // actionResponses:[]
  66. };
  67. user.appId = app_id;
  68. user.userId = userId;
  69. user.breakPointId = Number(this.configService.get('app.startPoint')) || 0;
  70. console.log('user-init', user);
  71. this.users[userId] = user;
  72. const reply = {
  73. traceIds: [],
  74. vehicle: null,
  75. mediaSrc: null,
  76. newUserStates: [
  77. {
  78. userId: 'dcff36ae4fc1d',
  79. playerState: {
  80. roomTypeId: '',
  81. person: 0,
  82. avatarId: '',
  83. skinId: '',
  84. roomId: '',
  85. isHost: false,
  86. isFollowHost: false,
  87. skinDataVersion: '',
  88. avatarComponents: '',
  89. nickName: '',
  90. movingMode: 0,
  91. attitude: '',
  92. areaName: '',
  93. pathName: '',
  94. pathId: '',
  95. avatarSize: 1,
  96. extra: '',
  97. prioritySync: false,
  98. player: {
  99. position: { x: 100.0, y: 100.0, z: 0.0 },
  100. angle: {
  101. pitch: 0,
  102. yaw: 0,
  103. roll: 0,
  104. },
  105. },
  106. camera: {
  107. position: { x: -338.0, y: 100, z: 120.0 },
  108. angle: {
  109. pitch: 0,
  110. yaw: 0,
  111. roll: 0,
  112. },
  113. },
  114. cameraCenter: { x: 100.0, y: 100.0, z: 0.0 },
  115. },
  116. renderInfo: {
  117. renderType: 0,
  118. videoFrame: null,
  119. cameraStateType: 3,
  120. isMoving: 0,
  121. needIfr: 0,
  122. isVideo: 0,
  123. stillFrame: 0,
  124. isRotating: 0,
  125. isFollowing: 0,
  126. clientPanoTitlesBitmap: [],
  127. clientPanoTreceId: '',
  128. prefetchVideoId: '',
  129. noMedia: false,
  130. },
  131. event: null,
  132. relation: 1,
  133. },
  134. ],
  135. actionResponses: [
  136. // {
  137. // "actionType": 15,
  138. // "pointType": 100,
  139. // "extra": "",
  140. // "traceId": "d0864cd0-378d-4d49-b7b0-3e8e1b9494c3",
  141. // "packetId": "d44bd2f5-f877-4dd7-868b-803c64f99082",
  142. // "nps": [],
  143. // "peopleNum": 0,
  144. // "zoneId": "",
  145. // "echoMsg": "",
  146. // "reserveDetail": null,
  147. // "userWithAvatarList": [],
  148. // "newUserStates": [],
  149. // "code": 0,
  150. // "msg": ""
  151. // }
  152. ],
  153. getStateType: 0,
  154. code: 0,
  155. msg: 'OK',
  156. };
  157. reply['newUserStates'][0]['userId'] = userId;
  158. this.replies[userId] = reply;
  159. return reply;
  160. }
  161. /**
  162. * delete User object
  163. * @param userId
  164. */
  165. deleteUser(userId: string) {
  166. if (userId in this.users) {
  167. delete this.users[userId];
  168. console.log('[delete User]--存在用户 %s', userId);
  169. }
  170. }
  171. // 顺序旋转请求
  172. seqExeRotate = seqExeAsyncFn(this.rotate);
  173. //旋转请求
  174. async rotate(actionRequest) {
  175. // return new Promise(async (resolve, reject) => {
  176. try {
  177. const userId = actionRequest['user_id'];
  178. if (this.actionRequestPool[userId]) {
  179. this.actionRequestPool[userId].push(actionRequest);
  180. } else {
  181. this.actionRequestPool[userId] = [];
  182. this.actionRequestPool[userId].push(actionRequest);
  183. }
  184. let reply = this.replies[userId];
  185. const actionRequests = this.actionRequestPool[userId];
  186. const user = this.users[userId];
  187. // debugger;
  188. let horizontal_move = user.rotateInfo.horizontal_move;
  189. //const traceIds = user.traceIds;
  190. let sub = 0;
  191. for (let i = 0; i < actionRequests.length; ++i) {
  192. if (actionRequests[i].action_type == this.Actions.Rotation) {
  193. horizontal_move += actionRequests[i].rotation_action.horizontal_move;
  194. reply.traceIds.push(actionRequests[i].trace_id);
  195. const actionResponse = this.createActionResponse(
  196. actionRequests[i].action_type,
  197. actionRequests[i].trace_id,
  198. );
  199. reply.actionResponses.push(actionResponse);
  200. ++sub;
  201. } else {
  202. break;
  203. }
  204. }
  205. actionRequests.splice(0, sub);
  206. const hAngle = horizontal_move * 90;
  207. if (Math.abs(hAngle) < 1) {
  208. user.rotateInfo.horizontal_move = horizontal_move;
  209. //user.traceIds = traceIds;
  210. this.replies[userId] = reply;
  211. return null;
  212. }
  213. reply = await this.rotateForAngle(userId, Math.floor(hAngle));
  214. // console.log('rotate-cameraAngle:, yaw: %s, ', user.camera.angle.yaw);
  215. return reply;
  216. // return resolve(reply);
  217. } catch (error) {
  218. throw error;
  219. // console.log('RotateService', error);
  220. // return reject(error);
  221. }
  222. // });
  223. }
  224. // test(){
  225. // while(true){
  226. // if(this.actionRequests.length>0){
  227. // let actionRequest = this.actionRequests[0];
  228. // //执行
  229. // //添加队列
  230. // }
  231. // }
  232. // }
  233. // receiveRotate(actionRequest){
  234. // this.actionRequests.push(actionRequest)
  235. // }
  236. async rotateForAngle(userId, hAngle): Promise<any> {
  237. return new Promise(async (resolve, reject) => {
  238. try {
  239. const user = this.users[userId];
  240. // console.log(
  241. // '当前镜头角度, yaw: %s, hAngle: %s',
  242. // user.camera.angle.yaw,
  243. // hAngle,
  244. // );
  245. // console.time('当前镜头角度 %s', user.camera.angle.yaw, '旋转角度:', hAngle);
  246. user.camera.angle.yaw += Math.floor(hAngle);
  247. if (user.camera.angle.yaw < 0) {
  248. user.camera.angle.yaw = 360 + user.camera.angle.yaw;
  249. } else if (user.camera.angle.yaw > 359) {
  250. user.camera.angle.yaw -= 360;
  251. }
  252. const reply = JSON.parse(JSON.stringify(this.replies[userId]));
  253. reply['newUserStates'][0]['userId'] = userId;
  254. //从redis里取
  255. //let key = user.appId + "-"+user.breakPointId+"-"+user.rotateInfo.frameIndex;
  256. let key =
  257. 'rotateframe:app_id:' +
  258. user.appId +
  259. ':frame_index:' +
  260. user.camera.angle.yaw +
  261. ':break_point_id:' +
  262. user.breakPointId;
  263. // const value = null;
  264. console.log('rotateForAngle-3:' + user.breakPointId);
  265. console.log('rotateForAngle-3-key:' + key);
  266. this.logger.log('rotateForAngle-3-key', key);
  267. let redisData = await this.cacheService.get(key);
  268. //if (redisData && redisData.length > 0) {
  269. let value = JSON.parse(redisData); //redisData ? JSON.parse(redisData) : null;
  270. //console.log('rotateForAngle-4:'+user.breakPointId+','+value.directory+','+value.fileName);
  271. if (value.directory != user.breakPointId) {
  272. key =
  273. 'rotateframe:app_id:' +
  274. user.appId +
  275. ':frame_index:' +
  276. user.camera.angle.yaw +
  277. ':break_point_id:' +
  278. user.breakPointId;
  279. redisData = await this.cacheService.get(key);
  280. value = JSON.parse(redisData);
  281. }
  282. // console.log('rotate-service', value);
  283. user.camera['position'] = JSON.parse(
  284. JSON.stringify(value.cameraPosition),
  285. ); //value ? value.cameraPosition : '';
  286. user.camera['angle'] = JSON.parse(JSON.stringify(value.cameraAngle)); //value ? value.cameraAngle : '';
  287. reply['newUserStates'][0]['playerState'].player.position = JSON.parse(
  288. JSON.stringify(user.player.position),
  289. );
  290. reply['newUserStates'][0]['playerState'].player.angle = JSON.parse(
  291. JSON.stringify(user.player.angle),
  292. );
  293. //this.reply['newUserStates'][0]['playerState'] .player
  294. reply['newUserStates'][0]['playerState'].camera.position = JSON.parse(
  295. JSON.stringify(value.cameraPosition),
  296. );
  297. reply['newUserStates'][0]['playerState'].camera.angle = JSON.parse(
  298. JSON.stringify(value.cameraAngle),
  299. );
  300. reply['newUserStates'][0]['playerState'].cameraCenter = JSON.parse(
  301. JSON.stringify(user.player.position),
  302. );
  303. // debugger
  304. reply.mediaSrc =
  305. '/' +
  306. user.appId +
  307. '/' +
  308. user.breakPointId +
  309. '/' +
  310. value.directory +
  311. '/' +
  312. value.fileName +
  313. '?m=' +
  314. new Date().getTime();
  315. console.log(
  316. 'rotateForAngle-5:' +
  317. user.breakPointId +
  318. ',' +
  319. value.directory +
  320. ',' +
  321. value.fileName,
  322. );
  323. reply.breakPointId = user.breakPointId;
  324. this.replies[userId].traceIds = [];
  325. this.replies[userId].actionResponses = [];
  326. user.rotateInfo.horizontal_move = 0;
  327. return resolve(reply);
  328. //}
  329. // else {
  330. // return null;
  331. // }
  332. } catch (error) {
  333. debugger;
  334. this.logger.error('rotateForAngle::function', error);
  335. return reject(error);
  336. }
  337. });
  338. }
  339. createActionResponse(actionType, traceId) {
  340. const actionResponse = {
  341. actionType: actionType,
  342. pointType: 100,
  343. extra: '',
  344. traceId: traceId,
  345. packetId: '',
  346. nps: [],
  347. peopleNum: 0,
  348. zoneId: '',
  349. echoMsg: '',
  350. reserveDetail: null,
  351. userWithAvatarList: [],
  352. newUserStates: [],
  353. code: 0,
  354. msg: '',
  355. };
  356. return actionResponse;
  357. }
  358. getNewUserStateRequest(actionRequest) {
  359. try {
  360. const userId = actionRequest['user_id'];
  361. const actionType = actionRequest['action_type'];
  362. const traceId = actionRequest['trace_id'];
  363. const reply = {
  364. actionType: actionType,
  365. pointType: 100,
  366. extra: '',
  367. traceId: traceId,
  368. packetId: '',
  369. nps: [],
  370. peopleNum: 0,
  371. zoneId: '',
  372. echoMsg: '',
  373. reserveDetail: null,
  374. userWithAvatarList: [],
  375. newUserStates: [],
  376. code: 0,
  377. msg: '',
  378. };
  379. const userIds = Object.keys(this.users);
  380. for (let i = 0; i < userIds.length; ++i) {
  381. const _user = this.users[userIds[i]];
  382. const newUserState = {
  383. userId: userIds[i],
  384. playerState: {
  385. roomTypeId: '',
  386. person: 0,
  387. avatarId: 'My_Actor',
  388. skinId: '0000000001',
  389. roomId: 'aea5406a-3099-48db-b428-30917872e58a',
  390. isHost: false,
  391. isFollowHost: false,
  392. skinDataVersion: '1008900008',
  393. avatarComponents: '',
  394. nickName: userIds[i],
  395. movingMode: 0,
  396. attitude: 'walk',
  397. areaName: '',
  398. pathName: 'thirdwalk',
  399. pathId: 'thirdwalk',
  400. avatarSize: 1,
  401. extra: '{"removeWhenDisconnected":true}',
  402. prioritySync: false,
  403. player: {
  404. position: _user.player.position,
  405. angle: _user.player.angle,
  406. },
  407. camera: null,
  408. cameraCenter: null,
  409. },
  410. renderInfo: {
  411. renderType: 0,
  412. videoFrame: null,
  413. cameraStateType: 0,
  414. isMoving: 0,
  415. needIfr: 0,
  416. isVideo: 0,
  417. stillFrame: 0,
  418. isRotating: 0,
  419. isFollowing: 0,
  420. clientPanoTitlesBitmap: [],
  421. clientPanoTreceId: '',
  422. prefetchVideoId: '',
  423. noMedia: false,
  424. },
  425. event: {
  426. id: '',
  427. type: 0,
  428. points: [],
  429. rotateEvent: null,
  430. removeVisitorEvent: null,
  431. },
  432. relation: 0,
  433. };
  434. reply['newUserStates'].push(newUserState);
  435. }
  436. return reply;
  437. } catch (error) {
  438. this.logger.error('getNewUserStateRequest::function', error);
  439. }
  440. }
  441. async echo(userId: string, isFirst: boolean) {
  442. const user = this.users[userId];
  443. const reply = JSON.parse(JSON.stringify(this.replies[userId]));
  444. reply['newUserStates'][0]['userId'] = userId;
  445. reply['newUserStates'][0]['playerState'].player.position =
  446. user.player.position;
  447. reply['newUserStates'][0]['playerState'].player.angle = user.player.angle;
  448. reply['newUserStates'][0]['playerState'].camera.position =
  449. user.camera['position'];
  450. reply['newUserStates'][0]['playerState'].camera.angle =
  451. user.camera['angle'];
  452. reply['newUserStates'][0]['playerState'].cameraCenter =
  453. user.player.position;
  454. if (isFirst) {
  455. reply.mediaSrc =
  456. '/' +
  457. user.appId +
  458. '/' +
  459. user.breakPointId +
  460. '/' +
  461. user.breakPointId +
  462. '/' +
  463. `${user.breakPointId}.0000.h264` +
  464. '?m=' +
  465. new Date().getTime();
  466. reply.breakPointId = user.breakPointId;
  467. return reply;
  468. } else {
  469. /*
  470. const key =
  471. 'rotateframe:app_id:' +
  472. user.appId +
  473. ':frame_index:' +
  474. user.camera.angle.yaw +
  475. ':break_point_id:' +
  476. user.breakPointId;
  477. const redisData = await this.cacheService.get(key);
  478. if (redisData && redisData.length > 0) {
  479. const value = redisData ? JSON.parse(redisData) : null;
  480. reply.mediaSrc =
  481. '/' +
  482. user.appId +
  483. '/' +
  484. user.breakPointId +
  485. '/' +
  486. value.directory +
  487. '/' +
  488. value.fileName +
  489. '?m=' +
  490. new Date().getTime();
  491. reply.breakPointId = user.breakPointId;
  492. // console.log(
  493. // 'joystick:->echo' +
  494. // 'playerPosition:' +
  495. // JSON.stringify(
  496. // reply['newUserStates'][0].playerState.player.position,
  497. // ) +
  498. // ',cameraPosition:' +
  499. // JSON.stringify(
  500. // reply['newUserStates'][0].playerState.camera.position,
  501. // ),
  502. // );
  503. */
  504. let fileName = user.camera.angle.yaw + '.h264';
  505. if (fileName.length == 8) {
  506. fileName = '0' + fileName;
  507. } else if (fileName.length == 7) {
  508. fileName = '00' + fileName;
  509. } else if (fileName.length == 6) {
  510. fileName = '000' + fileName;
  511. }
  512. reply.mediaSrc =
  513. '/' +
  514. user.appId +
  515. '/' +
  516. user.breakPointId +
  517. '/' +
  518. user.breakPointId +
  519. '/' +
  520. user.breakPointId +
  521. '.' +
  522. fileName +
  523. '?m=' +
  524. new Date().getTime();
  525. reply.breakPointId = user.breakPointId;
  526. return reply;
  527. // } else {
  528. // this.logger.error('echo返回null', key);
  529. // return {};
  530. }
  531. }
  532. }