rotate.service.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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. 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. const 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. const redisData = await this.cacheService.get(key);
  266. //if (redisData && redisData.length > 0) {
  267. const value = JSON.parse(redisData); //redisData ? JSON.parse(redisData) : null;
  268. // console.log('rotate-service', value);
  269. user.camera['position'] = JSON.parse(
  270. JSON.stringify(value.cameraPosition),
  271. ); //value ? value.cameraPosition : '';
  272. user.camera['angle'] = JSON.parse(JSON.stringify(value.cameraAngle)); //value ? value.cameraAngle : '';
  273. reply['newUserStates'][0]['playerState'].player.position = JSON.parse(
  274. JSON.stringify(user.player.position),
  275. );
  276. reply['newUserStates'][0]['playerState'].player.angle = JSON.parse(
  277. JSON.stringify(user.player.angle),
  278. );
  279. //this.reply['newUserStates'][0]['playerState'] .player
  280. reply['newUserStates'][0]['playerState'].camera.position = JSON.parse(
  281. JSON.stringify(value.cameraPosition),
  282. );
  283. reply['newUserStates'][0]['playerState'].camera.angle = JSON.parse(
  284. JSON.stringify(value.cameraAngle),
  285. );
  286. reply['newUserStates'][0]['playerState'].cameraCenter = JSON.parse(
  287. JSON.stringify(user.player.position),
  288. );
  289. // debugger
  290. reply.mediaSrc =
  291. '/' +
  292. user.appId +
  293. '/' +
  294. user.breakPointId +
  295. '/' +
  296. value.directory +
  297. '/' +
  298. value.fileName +
  299. '?m=' +
  300. new Date().getTime();
  301. console.log('rotateForAngle-4:' + user.breakPointId);
  302. reply.breakPointId = user.breakPointId;
  303. this.replies[userId].traceIds = [];
  304. this.replies[userId].actionResponses = [];
  305. user.rotateInfo.horizontal_move = 0;
  306. return resolve(reply);
  307. //}
  308. // else {
  309. // return null;
  310. // }
  311. } catch (error) {
  312. this.logger.error('rotateForAngle::function', error);
  313. return reject(error);
  314. }
  315. });
  316. }
  317. createActionResponse(actionType, traceId) {
  318. const actionResponse = {
  319. actionType: actionType,
  320. pointType: 100,
  321. extra: '',
  322. traceId: traceId,
  323. packetId: '',
  324. nps: [],
  325. peopleNum: 0,
  326. zoneId: '',
  327. echoMsg: '',
  328. reserveDetail: null,
  329. userWithAvatarList: [],
  330. newUserStates: [],
  331. code: 0,
  332. msg: '',
  333. };
  334. return actionResponse;
  335. }
  336. getNewUserStateRequest(actionRequest) {
  337. try {
  338. const userId = actionRequest['user_id'];
  339. const actionType = actionRequest['action_type'];
  340. const traceId = actionRequest['trace_id'];
  341. const reply = {
  342. actionType: actionType,
  343. pointType: 100,
  344. extra: '',
  345. traceId: traceId,
  346. packetId: '',
  347. nps: [],
  348. peopleNum: 0,
  349. zoneId: '',
  350. echoMsg: '',
  351. reserveDetail: null,
  352. userWithAvatarList: [],
  353. newUserStates: [],
  354. code: 0,
  355. msg: '',
  356. };
  357. const userIds = Object.keys(this.users);
  358. for (let i = 0; i < userIds.length; ++i) {
  359. const _user = this.users[userIds[i]];
  360. const newUserState = {
  361. userId: userIds[i],
  362. playerState: {
  363. roomTypeId: '',
  364. person: 0,
  365. avatarId: 'KGe_Boy',
  366. skinId: '10089',
  367. roomId: 'e629ef3e-022d-4e64-8654-703bb96410eb',
  368. isHost: false,
  369. isFollowHost: false,
  370. skinDataVersion: '1008900008',
  371. avatarComponents: '',
  372. nickName: userIds[i],
  373. movingMode: 0,
  374. attitude: 'walk',
  375. areaName: '',
  376. pathName: 'thirdwalk',
  377. pathId: 'thirdwalk',
  378. avatarSize: 1,
  379. extra: '{"removeWhenDisconnected":true}',
  380. prioritySync: false,
  381. player: {
  382. position: _user.player.position,
  383. angle: _user.player.angle,
  384. },
  385. camera: null,
  386. cameraCenter: null,
  387. },
  388. renderInfo: {
  389. renderType: 0,
  390. videoFrame: null,
  391. cameraStateType: 0,
  392. isMoving: 0,
  393. needIfr: 0,
  394. isVideo: 0,
  395. stillFrame: 0,
  396. isRotating: 0,
  397. isFollowing: 0,
  398. clientPanoTitlesBitmap: [],
  399. clientPanoTreceId: '',
  400. prefetchVideoId: '',
  401. noMedia: false,
  402. },
  403. event: {
  404. id: '',
  405. type: 0,
  406. points: [],
  407. rotateEvent: null,
  408. removeVisitorEvent: null,
  409. },
  410. relation: 0,
  411. };
  412. reply['newUserStates'].push(newUserState);
  413. }
  414. return reply;
  415. } catch (error) {
  416. this.logger.error('getNewUserStateRequest::function', error);
  417. }
  418. }
  419. async echo(userId: string, isFirst: boolean) {
  420. const user = this.users[userId];
  421. const reply = JSON.parse(JSON.stringify(this.replies[userId]));
  422. reply['newUserStates'][0]['userId'] = userId;
  423. reply['newUserStates'][0]['playerState'].player.position =
  424. user.player.position;
  425. reply['newUserStates'][0]['playerState'].player.angle = user.player.angle;
  426. reply['newUserStates'][0]['playerState'].camera.position =
  427. user.camera['position'];
  428. reply['newUserStates'][0]['playerState'].camera.angle =
  429. user.camera['angle'];
  430. reply['newUserStates'][0]['playerState'].cameraCenter =
  431. user.player.position;
  432. if (isFirst) {
  433. reply.mediaSrc =
  434. '/' +
  435. user.appId +
  436. '/' +
  437. user.breakPointId +
  438. '/' +
  439. user.breakPointId +
  440. '/' +
  441. `${user.breakPointId}.0000.h264` +
  442. '?m=' +
  443. new Date().getTime();
  444. reply.breakPointId = user.breakPointId;
  445. return reply;
  446. } else {
  447. /*
  448. const key =
  449. 'rotateframe:app_id:' +
  450. user.appId +
  451. ':frame_index:' +
  452. user.camera.angle.yaw +
  453. ':break_point_id:' +
  454. user.breakPointId;
  455. const redisData = await this.cacheService.get(key);
  456. if (redisData && redisData.length > 0) {
  457. const value = redisData ? JSON.parse(redisData) : null;
  458. reply.mediaSrc =
  459. '/' +
  460. user.appId +
  461. '/' +
  462. user.breakPointId +
  463. '/' +
  464. value.directory +
  465. '/' +
  466. value.fileName +
  467. '?m=' +
  468. new Date().getTime();
  469. reply.breakPointId = user.breakPointId;
  470. // console.log(
  471. // 'joystick:->echo' +
  472. // 'playerPosition:' +
  473. // JSON.stringify(
  474. // reply['newUserStates'][0].playerState.player.position,
  475. // ) +
  476. // ',cameraPosition:' +
  477. // JSON.stringify(
  478. // reply['newUserStates'][0].playerState.camera.position,
  479. // ),
  480. // );
  481. */
  482. let fileName = user.camera.angle.yaw + '.h264';
  483. if (fileName.length == 8) {
  484. fileName = '0' + fileName;
  485. } else if (fileName.length == 7) {
  486. fileName = '00' + fileName;
  487. } else if (fileName.length == 6) {
  488. fileName = '000' + fileName;
  489. }
  490. reply.mediaSrc =
  491. '/' +
  492. user.appId +
  493. '/' +
  494. user.breakPointId +
  495. '/' +
  496. user.breakPointId +
  497. '/' +
  498. user.breakPointId +
  499. '.' +
  500. fileName +
  501. '?m=' +
  502. new Date().getTime();
  503. reply.breakPointId = user.breakPointId;
  504. return reply;
  505. // } else {
  506. // this.logger.error('echo返回null', key);
  507. // return {};
  508. }
  509. }
  510. }